赞
踩
Ajax
readyState表示xhr对象的请求状态,取值范围是0——4,分别表示5个不同的状态。
0:(未初始化)xhr对象已经创建,但还没有调用open()方法。值为0表示对象已经存在,否则浏览器会报错:对象不存在。
1 :(载入/发送请求)调用open()方法对xhr对象进行初始化,根据参数(method,url,true),完成对象状态的设置。并调用send()方法开始向服务端发送请求。值为1表示正在向服务端发送请求。
2 :(载入完成/响应接收)接收服务器端响应回的数据。但获得的还只是服务端响应的原始数据,并不能直接在客户端使用。值为2表示send()请求方法执行完成,并已经接收完全部的响应数据(未解析)。
3 - (交互/解析数据)正在解析从服务器端接收到的响应数据。即根据服务器端响应头部返回的MIME类型把数据转换成能通过responseBody、responseText或responseXML属性存取的格式,为在客户端调用作好准备。值为3表示正在解析加载数据。
4 - (后台处理完成)响应内容解析完成,可以在客户端调用了。此阶段确认全部数据都已经解析为客户端可用的格式,解析已经完成。值为4表示数据解析完毕,可以通过XMLHttpRequest对象的相应属性取得数据。
总之,整个XMLHttpRequest对象的生命周期应该包含如下阶段:
创建-0初始化请求-1发送请求-2接收数据-3解析数据-4完成 。
Ajax 的原理简单来说是在⽤户和服务器之间加了—个中间层( AJAX 引擎),通过XmlHttpRequest 对象来向服务器发异步请求,从服务器获得数据,然后⽤ javascript来操作 DOM ⽽更新⻚⾯。使⽤户操作与服务器响应异步化。这其中最关键的⼀步就是从服务器获得请求数据
Ajax 的过程只涉及 JavaScript 、 XMLHttpRequest 和 DOM 。 XMLHttpRequest 是ajax的核⼼机制
/** 1. 创建连接 **/ var xhr = null; xhr = XMLHTTPRequest ? new XMLHttpRequest() : new window.ActiveXObject('Microsoft.XMLHTTP'); /** 2. 连接服务器 **/ xhr.open('get', url, true) /** 3. 发送请求 **/ xhr.send(null); /** 4. 接受请求 **/ xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if(xhr.status == 200){ success(xhr.responseText); } else { /** false **/ fail && fail(xhr.status); } } }
ajax 有那些优缺点?
优点:
通过异步模式,提升了⽤户体验.
优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占⽤.
Ajax 在客户端运⾏,承担了⼀部分本来由服务器承担的⼯作,减少了⼤⽤户量下的服务器负载。
Ajax 可以实现动态不刷新(局部刷新)
缺点:
安全问题 AJAX 暴露了与服务器交互的细节。
对搜索引擎的⽀持⽐较弱。
不容易调试。
表示一个空对象引用。
alert(null instanceof Object); 返回值为false,( null表示为空的引用;instanceof 表示某个变量是否是某个对象的实例)
图⽚懒加载,在⻚⾯上的未可视区域可以添加⼀个滚动事件,判断图⽚位置与浏览器顶端的距离与⻚⾯的距离,如果前者⼩于后者,优先加载。
如果为幻灯⽚、相册等,可以使⽤图⽚预加载技术,将当前展示图⽚的前⼀张和后⼀张优先下载。
如果图⽚为css图⽚,可以使⽤ CSSsprite , SVGsprite , Iconfont 、 Base64 等技术。
如果图⽚过⼤,可以使⽤特殊编码的图⽚,加载时会先加载⼀张压缩的特别厉害的缩略图,以提⾼⽤户体验。
如果图⽚展示区域⼩于图⽚的真实⼤⼩,则因在服务器端根据业务需要先⾏进⾏图⽚压缩,图⽚压缩后⼤⼩与展示⼀致。
优点:可以加密,减少了 HTTP 请求
缺点:是需要消耗 CPU 进⾏编解码
undefined + 1 === NaN,undefined将它强制转换成数值会返回NaN
<script type = "text/javascript"> function a () { //补充代码 var oLi = document.getElementByTagName("li"); for (let i = 0; i < oLi.length; i++) { oLi[i].index = i; oLi[i].onClick = function () { alert(this.index + 1); } } } </script> //闭包实现 var lis=document.querySelectorAll('li'); for (var i = 0; i < lis.length; i++) { var li = lis[i]; li.onclick=(function(index){ return function(e){ alert(index); }; })(i); }
vue.js 则是采⽤数据劫持结合发布者-订阅者模式的⽅式,通过Object.defineProperty() 来劫持各个属性的 setter , getter ,在数据变动时发布消息给订阅者,触发相应的监听回调
vue objectDefined proxy v-model
React并没有自带的双向绑定,需要自己实现,结合setState()以及onChange事件来实现,每次文本框改变文本(即触发onChange事件),就使用setState()改变state数据
import React, { Component } from "react" import ReactDOM from "react-dom" export default class DataBind extends Component{ constructor(props){ super(props) this.state = { value: "Name" } } handleChange(e){ this.setState({ value : e.target.value }) } render(){ return( <div style={{color:'black'}}> <input value={this.state.value} onChange={this.handleChange.bind(this)}></input> <p>{this.state.value}</p> </div> ) } }
Vue 的表单可以使⽤ v-model ⽀持双向绑定,相⽐于 React 来说开发上更加⽅便,当然了 v-model 其实就是个语法糖,本质上和 React 写表单的⽅式没什么区别
改变数据⽅式不同, Vue 修改状态相⽐来说要简单许多, React 需要使⽤ setState来改变状态,并且使⽤这个 API 也有⼀些坑点。并且 Vue 的底层使⽤了依赖追踪,⻚⾯更新渲染已经是最优的了,但是 React 还是需要⽤户⼿动去优化这⽅⾯的问题。
React 16 以后,有些钩⼦函数会执⾏多次,这是因为引⼊ Fiber 的原因。React 需要使⽤ JSX ,有⼀定的上⼿成本,并且需要⼀整套的⼯具链⽀持,但是完全可以通过 JS 来控制⻚⾯,更加的灵活。 Vue 使⽤了模板语法,相⽐于 JSX 来说没有那么灵活,但是完全可以脱离⼯具链,通过直接编写 render 函数就能在浏览器中运⾏。
在⽣态上来说,两者其实没多⼤的差距,当然 React 的⽤户是远远⾼于 Vue 的
通过⼀对⼀或者⼀对多的依赖关系,当对象发⽣改变时,订阅⽅都会收到通知。在现实⽣活中,也有很多类似场景,⽐如我需要在购物⽹站上购买⼀个产品,但是发现该产品⽬前处于缺货状态,这时候我可以点击有货通知的按钮,让⽹站在产品有货的时候通过短信通知我。在实际代码中其实发布-订阅模式也很常⻅,⽐如我们点击⼀个按钮触发了点击事件就是使⽤了该模式
vue数据双向绑定也用到了发布订阅模式
观察者模式和发布订阅模式最大的区别就是发布订阅模式有个**事件调度中心 **
观察者模式中观察者和目标直接进行交互,而发布订阅模式中统一由调度中心进行处理,订阅者和发布者互不干扰。这样一方面实现了解耦,还有就是可以实现更细粒度的一些控制。比如发布者发布了很多消息,但是不想所有的订阅者都接收到,就可以在调度中心做一些处理,类似于权限控制之类的。还可以做一些节流操作。
1.新增了块级作用域(let,const)
2.提供了定义类的语法糖(class)
3.新增了一种基本数据类型(Symbol)
4.新增了变量的解构赋值
5.函数参数允许设置默认值,新增了箭头函数。
6.数组新增了一些API,如isArray / from / of 方法;数组实例新增了 entries(),keys() 和 values() 等方法。
7.对象和数组新增了扩展运算符
8.ES6新增了模块化(import / export)
9.ES6新增了Set和Map数据结构。
10.ES6原生提供Proxy构造函数,用来生成Proxy实例
11.ES6新增了生成器(Generator)和遍历器(Iterator)
// 1. ...实现
let copy1 = {...{x:1}}
// 2. Object.assign实现
let copy2 = Object.assign({}, {x:1})
deepClone = (initalObj) => { const obj = {}; if(typeof initalObj !== 'object'){ return initalObj } for (const key in initalObj) { if (typeof initalObj[key] === 'object') { //对数组特殊处理 if (Array.isArray(initalObj[key])) { //用map方法返回新数组,将数组中的元素递归 obj[key] = initalObj[key].map(item => deepClone(item)) } else { //递归返回新的对象 obj[key] = deepClone(initalObj[key]); } } else if (typeof initalObj[key] === 'function') { //返回新函数 obj[key] = initalObj[key].bind(obj); } else { //基本类型直接返回 obj[key] = initalObj[key]; } } return obj; } // JSON.parse(JSON.stringify(obj))
//ES6 var arr = [1, [2, [3]], 4, [5]]; arr.flat(Infinity); //ES5第一种 function flatArr (arr) { var resultArr = []; arr.forEach(function (item) { //数组遍历最好用forEach var str = Object.prototype.toString.call(item); if (str.indexOf("Array") !== -1) { resultArr = resultArr.concat(flatArr(item)); }else { resultArr = resultArr.concat(item); } }); return resultArr; } //迭代 //对于把递归转换成迭代,很多情况下都需要一个stack来模拟函数调用。先看代码: function flatten2(arr) { const stack = [...arr]; const res = []; while (stack.length) { // 从栈里取出 const next = stack.pop(); if (Array.isArray(next)) { // 把next扁平化,然后放入stack中 stack.push(...next); } else { res.push(next); } } // reverse to restore input order return res.reverse(); } console.log(flatten2(arr)) 递归是重复调用函数自身实现循环。迭代是函数内某段代码实现循环,循环代码中参与运算的变量同时是保存结果的变量,当前保存的结果作为下一次循环计算的初始值。 递归循环中,遇到满足终止条件的情况时逐层返回来结束。迭代则使用计数器结束循环。当然很多情况都是多种循环混合采用,这要根据具体需求。 结构不同:递归与迭代都是基于控制结构:迭代用重复结构,而递归用选择结构。 //第二种 var tempArr = arr.toString().split(","); //arr.toString()的结果是"1, 2, 3, 4, 5", //arr.toString().split(",")结果为["1", "2", "3", "4", "5"] var resultArr = tempArr.map(function (item) { return parseInt(item); }); console.log(resultArr); //第三种 var tempArr = arr.join().split(","); var resultArr = tempArr.map(function (item) { return parseInt(item); }); console.log(resultArr);
方案一:通过ref直接调用子组件的方法;
//父组件中 <template> <div> <Button @click="handleClick">点击调用子组件方法</Button> <Child ref="child"/> </div> </template> <script> import Child from './child'; export default { methods: { handleClick() { this.$refs.child.sing(); }, }, } </script> //子组件中 <template> <div>我是子组件</div> </template> <script> export default { methods: { sing() { console.log('我是子组件的方法'); }, }, }; </script>
方案二:通过组件的 e m i t 、 emit、 emit、on方法;
//父组件中<template> <div> <Button @click="handleClick">点击调用子组件方法</Button> <Child ref="child"/> </div></template> <script>import Child from './child';export default { methods: { handleClick() { this.$refs.child.$emit("childmethod") //子组件$on中的名字 }, },}</script>//子组件中<template> <div>我是子组件</div></template><script>export default { mounted() { this.$nextTick(function() { this.$on('childmethods', function() { console.log('我是子组件方法'); }); }); },};</script>
至于项目中的$emit,是父子组件间传值
const removeRepeat1 = (arr) => {
const obj={};
return arr.filter(item=>{
if(!obj[item.toString()]) {
obj[item.toString()]=item.toString();
return true;
}
});
}
⽅法⼀、利⽤ES6 Set去重(ES6中最常⽤) function unique (arr) { return Array.from(new Set(arr)) } 或者[...new Set(arr)] ⽅法⼆、利⽤for嵌套for,然后splice去重(ES5中最常⽤) function unique(arr){ for(var i=0; i<arr.length; i++){ for(var j=i+1; j<arr.length; j++){ if(arr[i]==arr[j]){ //第⼀个等同于第⼆个,splice⽅法删除 arr.splice(j,1); j--; } } } return arr; } ⽅法三、利⽤indexOf去重 var array = []; for (var i = 0; i < arr.length; i++) { if (array .indexOf(arr[i]) === -1) { array .push(arr[i]) } return array; } ⽅法四、利⽤includes var array =[]; for(var i = 0; i < arr.length; i++) { if( !array.includes( arr[i]) ) {//includes 检测数组是否有某个值 array.push(arr[i]); } return array } ⽅法五、利⽤filter function unique(arr) { return arr.filter(function(item, index, arr) { //当前元素,在原始数组中的第⼀个索引==当前索引值,否则返回当前元素 return arr.indexOf(item, 0) === index; }); }
setInterval = () =>{ console.log(1) //使用递归 setTimeout(setInterval,1000);};setInterval()
render方法新增返回类型
render方法支持直接返回string,number,boolean,null,portal,以及fragments(带有key属性的数组),这可以在一定程度上减少页面的DOM层级
新的组件生命周期钩子
static getDerivedStateFromProps(nextProps, prevState)
componentDidCatch(error, info)
如果错误在组件的渲染或者生命周期方法中被抛出,则会触发该函数。
性能方面
lazy / Suspense
React.lazy() 提供了动态 import 组件的能力,实现代码分割。
Suspense 作用是在等待组件时 suspend(暂停)渲染,并显示加载标识。
React.Fragments
这样并不会在DOM中增加额外节点,相当于 render 返回数组元素。
Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到Vue 的官方调试工具 devtools extension ,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。当我们构建中大型SPA(单页面应用)项目时,Vuex则从中具有非常大的作用。
Vuex的应用场景
涉及到非父子组件之间的传值,例如兄弟关系、祖孙关系,甚至更远的关系组件之间的联系,如果使用传统父子组件之间传值的方式时,对开发人员来说可能是噩梦;
中大型单页应用,考虑如何更好地在组件外部管理状态;
特性:闭包是能够读取其他函数内部变量的函数,即在外面可以调用函数中的函数的变量,其实他就是将函数内外部连接起来的桥梁
//事例:<script type='text/javascript'> function a(){ var i = 99; iAdd = function(){ i++; } function b(){ alert(i); } return b; } var result = a(); result();//结果为99 iAdd(); result();//结果为100</script>
ES5 的继承时通过 prototype 或构造函数机制来实现。ES5 的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到 this 上(Parent.apply(this))。ES6 的继承机制完全不同,实质上是先创建父类的实例对象 this(所以必须先调用父类的 super()方法),然后再用子类的构造函数修改this。具体的:ES6 通过 class 关键字定义类,里面有构造方法,类之间通过 extends 关键字实现继承。子类必须在 constructor 方法中调用 super 方法,否则新建实例报错。因为子类没有自己的 this 对象,而是继承了父类的 this 对象,然后对其进行加工。如果不调用 super 方法,子类得不到 this 对象。ps:super 关键字指代父类的实例,即父类的 this 对象。在子类构造函数中,调用 super 后,才可使用 this 关键字,否则报错。
方式 hash history
跳转 this.$router.push() <router-link to=""></router-link>
占位 <router-view></router-view>
https://www.cnblogs.com/LazyPet/p/12170995.html
前端路由原理?两种实现⽅式有什么区别?
前端路由实现起来其实很简单,本质就是监听 URL 的变化,然后匹配路由规则,显示相应的⻚⾯,并且⽆须刷新⻚⾯。⽬前前端使⽤的路由就只有两种实现⽅式
Hash 模式
www.test.com/#/ 就是 Hash URL ,当 # 后⾯的哈希值发⽣变化时,可以通过 onhashchange 事件来监听到 URL 的变化,从⽽进⾏跳转⻚⾯,并且⽆论哈希值如何变化,服务端接收到的 URL 请求永远是 www.test.com
window.addEventListener(‘hashchange’, () => {
// … 具体逻辑
})
Hash 模式相对来说更简单,并且兼容性也更好
History 模式 History 模式是 HTML5 新推出的功能,主要使⽤ history.pushState和 history.replaceState 改变 URL 通过 History 模式改变 URL 同样不会引起⻚⾯的刷新,只会更新浏览器的历史记录。当⽤户做出浏览器动作时,⽐如点击后退按钮时会触发 popState 事件
两种模式对⽐
Hash 模式只可以更改 # 后⾯的内容, History 模式可以通过 API 设置任意的同源URL
History 模式可以通过 API 添加任意类型的数据到历史记录中, Hash 模式只能更改哈希值,也就是字符串
Hash 模式⽆需后端配置,并且兼容性好。 History 模式在⽤户⼿动输⼊地址或者刷新⻚⾯的时候会发起 URL 请求,后端需要配置 index.html ⻚⾯⽤于匹配不到静态资源的时候
补
computed 和 watch 区别
computed 是计算属性,依赖其他属性计算值,并且 computed 的值有缓存,只有当计算值变化才会返回内容。
watch 监听到值的变化就会执⾏回调,在回调中可以进⾏⼀些逻辑操作。
所以⼀般来说需要依赖别的属性来动态获得值的时候可以使⽤ computed ,对于监听到值的变化需要做⼀些复杂业务逻辑的情况可以使⽤ watch 。
另外 computer 和 watch 还都⽀持对象的写法,这种⽅式知道的⼈并不多。
补
keep-alive 组件有什么作⽤
如果你需要在组件切换的时候,保存⼀些组件的状态防⽌多次渲染,就可以使⽤ keepalive 组件包裹需要保存的组件。
对于 keep-alive 组件来说,它拥有两个独有的⽣命周期钩⼦函数,分别为 activated和 deactivated 。⽤ keep-alive 包裹的组件在切换时不会进⾏销毁,⽽是缓存到内存中并执⾏ deactivated 钩⼦函数,命中缓存渲染后会执⾏ actived 钩⼦函数。
https://blog.csdn.net/m0_48560510/article/details/110354840
进入首页时两次加载一个文档,优化代码当是登录页面跳转过来的才加载,可以通过导航守卫来实现,还可以有三种方法,query传参 params传参和直接路径拼接this.$router.push(’/index?from=login’),说明是从登录页面过来的,带有login的参数
query传参,其实是get传参,在地址栏里会拼接登录地址this.$router.push({ path: '/index', query: { from: 'login' }})params传参,路径没有进行拼接,但是是由参数的this.$router.push({ name: 'index',不是路径,应该是路由的名称 params: { from: 'login' }
})
获取参数时用this.
r
o
u
t
e
,
route,
route,route是路由实例,而$router是全局路由,整个路由都在里面(11-4)
可以通过query
,param
两种方式
区别:query
通过url
传参,刷新页面还在;params
属性页面不在
params的类型:
配置路由格式:/router/:id
传递的方式:在path
后面跟上对应的值
传递后形成的路径:/router/123
// 动态路由params在App.vue中<router-link :to="'/user/'+userId" replace>用户</router-link>在index.js { path:"/user/:userid", component:User, }
跳转方式:
// 方法1:<router-link :to="{ name: 'users', params: { uname: wade }}">按钮</router-link>// 方法2:this.$router.push({name:'users',params:{uname:wade}})// 方法3:this.$router.push('/user/' + wade)
可以通过$route.params.userid 获取你说传递的值
query的类型
<!--动态路由-query -->//01-直接在router-link 标签上以对象的形式<router-link :to="{path:'/profile',query:{name:'why',age:28,height:188}}">档案</router-link>/* 02-或者写成按钮以点击事件形式 <button @click='profileClick'>我的</button> */ //点击事件 profileClick(){ this.$router.push({ path: "/profile", query: { name: "kobi", age: "28", height: 198 } });
跳转方法:
// 方法1:<router-link :to="{ name: 'users', params: { uname: wade }}">按钮</router-link>// 方法2:this.$router.push({name:'users',params:{uname:wade}})// 方法3:this.$router.push('/user/' + wade)
可以通过$route.query 获取你所传递的值
vue-router提供的导航钩子主要用来拦截导航,让它完成跳转或取消。
导航钩子的分类
yarn add react-router-dom
在最外面的App.js里
import { BrowserRouter, Route } from ‘react-router-dom’;
在组件的render()里
<BrowserRouter> <div> <Route path='/' exact render={()=><div>home</div>}></Route> <Route path='/detail' exact render={()=><div>detail</div>}></Route> </div> </BrowserRouter>
代表的是路由说明里面内容要用路由了,它里面只能有一个children
Route代表的是路由规则
exact指只有路径完全相同才显示,否则只要路径包含就显示(8-1)
单页面应用就不能用<a href=’/detail’>…</a>
要使用Link
import { Link } from ‘react-router-dom’;
<Link to=’/detail’>…</Link>
注意:使用Link标签的组件必须放在总的文件<BrowserRouter></BrowserRouter>内部(8-10)
对比<a>,Link组件避免了不必要的重渲染 react-router:只更新变化的部分从而减少DOM性能消耗
react的创新之处在于,它利用虚拟DOM的概念和diff算法实现了页面的“按需加载”
var test = (function (a) {
this.a = a;
return function (b) {
return this.a + b;
}}(function(a, b) {
return a;
}(1, 2)));
console.log(test(4));
输出结果:5(1+4)
(function(a, b) {
return a;
}(1, 2))
回的是1,传给atest相当于
test = function (b) {
return this.a + b;
}b是4
一、vue-loader作用:
解析和转换.vue文件。提取出其中的逻辑代码 script,样式代码style,以及HTML 模板template,再分别把他们交给对应的loader去处理
二、用途
js可以写es6,style样式可以写scss或less、template可以加jade等
三、
css-loader:加载由vue-loader提取出的CSS代码
vue-template-compiler:把vue-loader提取出的HTML模板编译成可执行的javascript代码
splice(index,len,[item]) 注释:该方法会改变原始数组。注:concat不会改变原数组,需要有个变量来承接一下。
delete arr[1] delete删除掉数组中的元素后,会把该下标出的值置为undefined,数组的长度不会变
delete只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。
Vue.delete 直接删除了数组 改变了数组的键值。
https://www.cnblogs.com/qidh/p/11431998.html
https://www.cnblogs.com/wangjiachen666/p/9497749.html
D、多个宽高不等的元素,实现无缝瀑布流布局
答案:D
A.严格模式下,普通函数中没有直接调用者的函数中this指向window
B.普通函数中this指向它的直接调用者
C.普通函数中使用call绑定的this指向绑定的对象
D.箭头函数中的this指向定义它时所处的宿主对象
A为undefined
var obj1 = { a: 'a1', b: function () {return this.a}, c: function (obj) { obj = {a : 'a2'}; return this.a; }}var getFunctionB = obj1.b;var res1 = obj1.b();var res2 = getFunctionB();var res3 = obj1.c(obj1);
var dateStr = 'Friday';(function () { if (typeOf dateStr === 'undefined') { var dateStr = 'Staurday'; console.log('Hello' + dateStr); }else { console.log('Happy' + dateStr); }})();输出’Hello Staurday’var str = 'World!'; (function (name) { if (typeof name === 'undefined') { var name = 'Jack'; console.log('Goodbye ' + name); } else { console.log('Hello ' + name); }})(str);输出Hello World 因为name已经变成函数内局部变量
var [x, y = “b”] = [“a”, undefined];//x = “a”, y = “b”
var [x = 1] = [undefined];//x = 1
var [y = 1] = [null];//y = null
排序算法的稳定性,通俗地讲就是能保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。在简单形式化一下,如果Ai = Aj, Ai原来在位置前,排序后Ai还是要在Aj位置前。
margin: auto;
flex
绝对定位,反方向平移宽和高的一半
table vertical-align: middle;
/**⽅法⼀:已知元素的⾼宽**/ \#div1{ background-color:#6699FF; width:200px; height:200px; position: absolute; //⽗元素需要相对定位 top: 50%; left: 50%; margin-top:-100px ; //⼆分之⼀的height,width margin-left: -100px; } //不知道宽高 width: 78px; height: 78px; position: absolute; left: 50%; top: 50%; transform: translateX(-50%) translateY(-50%); // display:flex; justify-content: center; align-items: center; /**⽅法⼆:**/ \#div1{ width: 200px; height: 200px; background-color: #6699FF; margin:auto; position: absolute; //⽗元素需要相对定位***
如何垂直居中⼀个 <img> ?(⽤更简便的⽅法。)
#container {
display: table-cell;
text-align: center;
verticle-align: middle;
}
text-align: center
margin: 0 auto
display:flex + justify-content: center
display:flex + align-items: center
//升序arr.sort((a, b) => {return a-b;})
可以使用js和无序列表的方式;CSS动画过渡的方式,仔细看这两种实现方式的代码
https://www.jianshu.com/p/bd1f34e7e953
v-show 只是在 display: none 和 display: block 之间切换。⽆论初始条件是什么
都会被渲染出来,后⾯只需要切换 CSS , DOM 还是⼀直保留着的。所以总的来说 v-show 在初始渲染时有更⾼的开销,但是切换开销很⼩,更适合于频繁切换的场景。
v-if 的话就得说到 Vue 底层的编译了。当属性初始为 false 时,组件就不会被渲染,直到条件为 true ,并且切换条件时会触发销毁/挂载组件,所以总的来说在切换时开销更⾼,更适合不经常切换的场景。并且基于 v-if 的这种惰性渲染机制,可以在必要的时候才去渲染组件,减少整个⻚⾯的初始渲染开销。
置换元素是指根据标签和属性来决定元素的具体显示内容,置换元素在其显示中生成了框,这就是有的内嵌元素能够设置宽高的原因。元素img input textarea select object。大多数元素都是不可置换。label p
一个对象在其生命周期内,保持不变就是可哈希的hashable,例如字符串。可改变的就是不可哈希的unhashable,列表
require.js是js的轻量化框架,用于提高代码质量
CommonJS、AMD、CMD是用于JavaScript模块管理的三大规范
CommonJS定义的是模块的同步加载,是一个更偏向于服务器端的规范(也可以在浏览器中使用),主要用于Nodejs,根据CommonJS规范,一个单独的文件就是一个模块,加载模块使用require()方法,该方法读取一个文件并执行,最后返回文件内部的exports对象。
AMD和CMD则是定义模块异步加载适用于浏览器端,都是为了 JavaScript 的模块化开发,(这里说一下为什要有异步加载,因为浏览器如果使用common.js同步加载模块的话,就会导致性能等问题,所以针对这个问题,又出了一个规范,这个规范可以实现异步加载依赖模块)
AMD规范会提前加载依赖模块,AMD规范是通过requireJs 在推广过程中对模块定义的规范化产出。RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。推崇依赖前置。AMD 推荐的⻛格通过返回⼀个对象做为模块对象
CMD规范会延迟加载依赖模块, CMD 规范是 SeaJs 在推广过程中对模块定义的规范化产出。推崇依赖就近。 CommonJS 的⻛格通过对module.exports 或 exports 的属性赋值来达到暴露模块对象的⽬的
async函数就是generator函数的语法糖。
async函数,就是将generator函数的*换成async,将yield替换成await。
async函数对generator的改进
(1)内置执行器,不需要使用next()手动执行。
(2)await命令后面可以是Promise对象或原始类型的值,yield命令后面只能是Thunk函数或Promise对象。
(3)返回值是Promise。返回非Promise时,async函数会把它包装成Promise返回。(Promise.resolve(value))
作用
异步编程的终极解决方案。
通俗理解
async/await,就是异步编程回调函数写法的替代方法。(使代码以同步方式的写法完成异步操作)函数执行时,一旦遇到await就会返回。等到触发的异步操作完成(并且调用栈清空),再接着执行函数体内后面的语句。
await语句后面的代码,相当于回调函数。(即:await的下一行开始,都视作回调函数的内容)
回调函数会被压入microtask队列,当主线程调用栈被清空时,去microtask队列里取出各个回调函数,逐个执行。
Redux是什么呢?一个状态管理工具。那是干嘛用的呢?都知道,React可以进行单页应用(SPA)的开发,可以对页面中各个模块进行分割形成组件,而组件之间就避免不了事件的传递或数据的交互,那Redux就是用来对这些组件的状态进行管理的。
https://segmentfault.com/a/1190000008736866
WebPack 是⼀个模块打包⼯具,你可以使⽤ WebPack 管理你的模块依赖,并编绎输出模块们所需的静态⽂件。它能够很好地管理、打包 Web 开发中所⽤到的 HTML 、Javascript 、 CSS 以及各种静态⽂件(图⽚、字体等),让开发过程更加⾼效。对于不同类型的资源, webpack 有对应的模块加载器。 webpack 模块打包器会分析模块间的依赖关系,最后⽣成了优化且合并后的静态资源
函数前面多了一个async关键字。await关键字只能用在async定义的函数内。async函数会引式返回一个promise,改promise的resolve值就是函数return的值。
简洁:使用async和await明显节约了不少代码,不需要.then,不需要写匿名函数处理promise的resolve的值,不需要定义多余的data变量,还避免了嵌套代码。
async/await让try/catch 可以同时处理同步和异步错误。try/catch不能处理JSON.parse的错误,因为他在promise中。此时需要.catch,这样的错误处理代码非常冗余。并且,在我们的实际生产代码会更加复杂
条件语句
设置过期时间失效(只要设置了过期时间cookie就会存储在硬盘里面)
当会话结束时失效,即关闭浏览器窗口(如果没有设置Expires,cookie就会存储在内存里面)
回调函数,这是异步编程最基本的方法。
事件监听,另一种思路是采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。
发布/订阅
Promises对象,Promises 对象是CommonJS 工作组提出的一种规范,目的是为异步编程提供统一接口。
https://cloud.tencent.com/developer/article/1499717
promise generator async
意外的全局变量引起的内存泄露leak=“xxx”;//leak**成为一个全局变量,不会被回收
闭包
没有清理的DOM元素引用
定时器的第一个参数不是函数而是字符串
循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
子元素存在引起的内存泄露
可⽤ chrome 中的 timeline 进⾏内存标记,可视化查看内存的变化情 况,找出异常点。
怎样避免内存泄露
1)减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收;
2)注意程序逻辑,避免“死循环”之类的 ;
3)避免创建过多的对象 原则:不用了的东西要及时归还。
https://blog.csdn.net/michael8512/article/details/77888000
模块化 js scss
组件化
规范化 HTML css js规范 命名规范 前后端接口规范
自动化
//方法调用模式var blogInfo={ blogId:123, blogName:"werwr", showBlog:function(){alert(this.blogId);}};blogInfo.showBlog();//函数调用模式var myfunc = function(a,b){ return a+b;}alert(myfunc(3,4));//构造器调用模式var myfunc = function(a){ this.a = a;};myfunc.prototype = { show:function(){alert(this.a);}}var newfunc = new myfunc("123123123");newfunc.show();//apply,call调用模式var myobject={};var sum = function(a,b){ return a+b;};var sum2 = sum.call(myobject,10,30); //var sum2 = sum.apply(myobject,[10,30]); alert(sum2);
#div:hover {} //hover的位置
var cityData = [{
id: 1,
name: ‘广东省’,
children: [{
id: 11,
name: ‘深圳’}]
}]
//直接想到用递归来做吧~,先获取最外层的元素,判断id是否相等,不相等就继续判断是否含有子节点,然后继续递归循坏const recursion = (cityData, id) => { if (!cityData || !cityData.length) { return; } //先循坏cityData for (let i = 0; i < cityData.length; i++) { const childs = cityData[i].children; if (cityData[i].id === id) { result = cityData[i].name; } if (childs && childs.length > 0) { recursion(childs, id); } } return result;}console.log(recursion(cityData, 122))//灵芝
Vue的MVVM模型讲的是 model(数据模型),view(视图、模板),VM-> ViewModel,VM是M和V之间的桥梁
响应式 :vue如何监听到data的每个属性变化?
利用Object.defineProperty定义属性,将data里面的属性代理到vm上
模板解析: vue的模板如何被解析,指令如何处理?
这个模板里的html有逻辑,v-for, v-if等等,最终必须解析成html来显示,模板最终必须转换成 JS 代码
因为:
有逻辑(v-if v-for),必须用 JS 才能实现( 图灵完备)
转换为 html 渲染页面,必须用 JS 才能实现
因此,模板最重要转换成一个 JS 函数
with 用法:with 语句可以方便地用来引用某个特定对象中已有的属性,但是不能用来给对象添加属性。要给对象创建新的属性,必须明确地引用该对象。
render 函数
VUE一般使用template来创建HTML,然后在有的时候,我们需要使用javascript来创建html,这时候我们需要使用render函数。
Vue的实现流程
1、首先模板解析器解析成render函数
2、响应式监听
3、将数据渲染进模板里
4、data属性变化,触发render
action是处理异步任务的或者繁琐的同步任务的
mutation是处理同步任务的
对称加密
非对称加密
对称加密+非对称加密结合
https://blog.csdn.net/qq_29996285/article/details/84284524
浏览器先查找当前的url是否存在缓存,并比较缓存是否过期
没有缓存,浏览器将当前的url发送给DNS服务器解析url对应的IP地址
根据IP地址建立TCP连接
HTTP发起请求
服务器处理请求,浏览器接收HTTP响应
渲染页面,构建DOM树
关闭TCP连接
vue中nextTick()方法是将回调函数延迟在下一次dom更新数据后调用,简单的理解是:当数据更新了,在dom中渲染后,自动执行该函数,
process.nextTick()的意思就是定义出一个动作,并且让这个动作在下一个事件轮询的时间点上执行。
function foo() {
console.error('foo');
}
process.nextTick(foo);
console.error('bar');
//先输出'bar',再输出'foo'
因为浏览器会有并发请求限制,在 HTTP / 1.1 时代,每个请求都需要建⽴和断开,消耗了好⼏个 RTT 时间,并且由于 TCP 慢启动的原因,加载体积⼤的⽂件会需要更多的时间
在 HTTP / 2.0 中引⼊了多路复⽤,能够让多个请求使⽤同⼀个 TCP 链接,极⼤的加快了⽹⻚的加载速度。
并且还⽀持 Header 压缩,进⼀步的减少了请求的数据⼤⼩
function findLongestCommonStr(s1, s2) {
var commonStr = '', L1 = s1.length, L2 = s2.length;
var shortStr = L1>L2 ? s2 : s1;
var longStr = L1>L2 ? s1 : s2;
var strLen = shortStr.length;
for (let j = strLen; j > 0; j--) {
for (let i = 0, k = j; i <= strLen - j; i++, k++) {
commonStr = shortStr.subString(i, k);
if (longStr.indexOf(commonStr) >= 0) return commonStr;
}
}
return '';
}
//主线程直接执行console.log('1');//丢到宏事件队列中setTimeout(function() { console.log('2'); process.nextTick(function() { console.log('3'); }) new Promise(function(resolve) { console.log('4'); resolve(); }).then(function() { console.log('5') })})//微事件1process.nextTick(function() { console.log('6');})//主线程直接执行new Promise(function(resolve) { console.log('7'); resolve();}).then(function() { //微事件2 console.log('8')})//丢到宏事件队列中setTimeout(function() { console.log('9'); process.nextTick(function() { console.log('10'); }) new Promise(function(resolve) { console.log('11'); resolve(); }).then(function() { console.log('12') })})//1 7 6 8 2 4 3 5 9 11 10 12
async function async1() { console.log('async1 start') await async2() console.log('async1 end')} async function async2() { console.log('async2')} console.log('script start')setTimeout(function() { console.log('setTimeout')}, 0) async1(); new Promise( function( resolve ) { console.log('promise1') resolve();} ).then( function() { console.log('promise2')} ) console.log('script end')script startasync1 startasync2promise1script endpromise2async1 endsetTimeout首先,事件循环从宏任务(macrostack)队列开始,这个时候,宏任务队列中,只有一个 script (整体代码)任务。从宏任务队列中取出一个任务来执行。首先执行 console.log('script start'),输出 ‘script start'遇到 setTimeout 把 console.log('setTimeout') 放到 macrotask 队列中执行 aync1() 输出 ‘async1 start' 和 'async2' ,把 console.log('async1 end') 放到 micro 队列中执行到 promise ,输出 'promise1' ,把 console.log('promise2') 放到 micro 队列中执行 console.log('script end'),输出 ‘script end'macrotask 执行完成会执行 microtask ,把 microtask quene 里面的 microtask 全部拿出来一次性执行完,所以会输出 'async1 end' 和 ‘promise2'开始新一轮的事件循环,去除执行一个 macrotask 执行,所以会输出 ‘setTimeout'
Object.defineProperty()有以下2个非常明显的缺点:
(1)无法监听数组的变化。
(2)只能劫持对象的属性,无法劫持一个完整的对象。
对于实现双向数据绑定,更好的方法是使用Proxy对象来实现,如何实现
两种方式都要手撕代码
Class Rectangle { constructor(width, height) { this.width = width; this.height = height; } getArea() { return this.width * this.height; }}
Vue是渐进式的JavaScript框架
优点:压缩后体积小,效率高(虚拟DOM)、双向绑定、成熟框架
功能:v-bind v-on v-if v-show v-text v-html 组件 双向绑定
URI 是统一资源标识符,而 URL 是统一资源定位符。
每个 URL 都是 URI,但不一定每个 URI 都是 URL。这是因为 URI 还包括一个子类,即统一资源名称 (URN),它命名资源但不指定如何定位资源。
/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/
TCP和UDP都是传输层的协议
UDP提供了不可靠的无连接传输服务;TCP提供了可靠的面向连接的字节流传输协议
var towSum = function(nums, target){ for(let i=0, len = nums.length; i< len; i++) { if(nums.indexOf(target - nums[i]) > -1 ) { return [i, nums.indexOf(target - nums[i])] } }}//var towSum = function(nums, target){ let obj = {}; for(let i=0, len=nums.length; i< len; i++){ let mult = target - nums[i]; if(mult in obj){ return [obj[mult], i]; } obj[nums[i]] = i; }}//var towSum = function(nums, target){ for(let i=0, len = nums.length; i<len; i++) { for(let j = i+1; j < nums.length; j++) { if(nums[i] + nums[j] == target) { return [i, j] } } }}
对于多个组件的connect和store进行连接,一旦store内部修改了,那么每个组件都会重新渲染,也就是每个组件的render都会重新执行,解决这个问题可以使用之前的shouldComponentUpdate,react内部有PureComponent解决这个问题,只要把之前的引入包括使用Component的地方都改为PureComponent
import React, { PureComponent } from ‘react’;
因为使用了immutable.js这个框架,PureComponent和immutable.js能完美结合,但是如果不使用immutable.js就使用PureComponent的话,那么会遇到一些底层问题的坑,所以如果不使用immutable.js,最好自己写一个shouldCompomentUpdate来进行代码优化,不要使用PureComponent
no-cache
如果request headers中,Cache-Control为no-cache。表示不管服务端有没有设置Cache-Control,都必须从重新去获取请求。 浏览器缓存,但是认为是过期缓存
max-age=0
max-age=0表示不管response怎么设置,在重新获取资源之前,先检验ETag/Last-Modified
不管是max-age=0还是no-cache,都会返回304(资源无修改的情况下),no-store才是真正的不进行缓存。
1.减少全局变量
//达到每次调用函数add(),a都不断加1
function add(){ var a = 0; a++; alert(a);}add();add();//这样做每次调用a都从0开始//这样可以实现累加效果var a = 0;function add() { a++; alert(a);}add();add();//但这样做就增加全局变量//改为闭包的方式function f(){ var a = 0; return function(){ a++; alert(a); }}var result = f();result();result();
2.减少传递给函数的参数数量
//实现例如基数为2,最大数为3,返回值为2+ 1+2+3的值
//可以这样实现
function add(base,max){…}
//用闭包function calFactory(base){ return function(max){ var total = 0; for(var i = 1, i <= max, i++ ){ total +=i; } return total + base; }}var adder = calFactory(2);adder(3);//8//2+1+2+3adder(4);//12//2+1+2+3+4
3.起到封装的作用
(function(){ var m = 0; function getM(){//闭包 return m; } function setM(){//闭包 m = val; } window.g = getM;//通向外部的接口 window.s = setM;})();//立即调用的匿名函数s(12);alert(g());
1.对于捕获到的变量只是个饮用,不是复制
function f(){ var num = 1; function g(){ alert(num);//引用父的num } num++; g();//2}
2.父函数每调用一次,会产生不同的闭包
function f(){ var num = 1; return function(){ num++; alert(num); }}var result1 = f();//由函数的预处理可知,每次调用一个函数的时候会创建一个新的词法环境result1();//2result1();//3var result2 = f();//创建一个新的词法环境result2();//2result2();//3
3.循环中的问题
<body> <div id = “1”>1</div> <div id = “2”>2</div> <div id = “3”>3</div> for(var i = 1;i <=3;i++){ var ele = document.getElementById(”i”); ele.onclick = function(){ alert(i); } } </body> //点击1 2 3 都会弹出4,因为没有块级作用域,所以i相当于全局变量 //解决办法,可以用闭包 <body> <div id = “1”>1</div> <div id = “2”>2</div> <div id = “3”>3</div> (for(var i = 1;i <=3;i++){ var ele = document.getElementById(”i”); ele.onclick = (function(id){ return function(){ alert(id); } })(i);//每次点击1或2或3都会立即执行函数,从而达到点击几弹出几的效果 //每被调用一次函数,父函数的i都会被捕获,都会重新产生一个闭包 </body>
this永远指向对象
this可以直接写在全局里面,并且此时永远指向window对象;this也可以写在函数里面,此时氛围三种情况:
第一种情况:
var ele = document.getElementById(”id”);
ele.addElementListener(”click”,function{
console.log(this);//这种情况this永远指向引发事件的对象ele
})
第二种情况:
//this的指向是运行时决定,不是编写代码时决定
//运行时函数是谁调用的,this就指向谁
var o = { name:”nice”; print:function(){ console.log(this.name); }}o.print();//nice//函数是o调用的var ff = o.print;ff();//undefined//此时相当于window.ff(),函数是window调用的
第三种情况:
function f(){
this.name = “nice”;
}
上面第二种情况改变了this的指向,还可以使用call或apply或bind改变this指向,call和apply和bind都是函数对象都会有的东西
传参的时候call使用参数列表的形式,一个一个地传,而apply使用参数数组的形式
var o = { name:”nice”; print:function(){ console.log(this.name); } } var ff = o.print; ff();//undefined this.name = “global”; this.age = 22; ff();//global function log(a,b){ console.log(this[a]); console.log(this[b]); } log(”name”,”age”);//global 22 log.call(o,”name”);//nice//改变了this的指向,相当于o.log(“name”) log.call(o,”name”,”age”);//nice undefined//undefined因为在o对象中没有age变量 log.apply(o,[’’name”,”age”])//nice undefined
用迭代
var s = "1122333455";var cc = s.match(/(\d)\1+/g); //11,22,333,55 s1 = s.replace(cc[i], "");
ES6的解构let a = 1,b = 2;[a, b] = [b, a];var a = 1,b = 2;a = [a, b];b = a[0];a = a[1];
ECMAScript 提供了 3 个特殊的引用类型:Boolean、Number和 String。这些类型与其他引用类型相似,但同时也具有与各自的基本类型相应的特殊行为。
实际上,每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而能够调用一些方法来操作这些数据。
包装对象:
包装对象,就是当基本类型以对象的方式去使用时,JavaScript会转换成对应的包装类型,相当于new一个对象,内容和基本类型的内容一样,然后当操作完成再去访问的时候,这个临时对象会被销毁,然后再访问时候就是undefined。number,string,boolean都有对应的包装类型。 number,string,boolean都有对应的包装类型
因为有了基本包装类型,所以JS中的基本类型值可以被当作对象来访问;
基本类型特征:
1.每个包装类型都映射到同名的基本类型;
2.在读取模式下访问基本类型值时,就会创建对应的基本包装类型的一个对象,从而方便了数据操作;
3.操作基本类型值的语句一经执行完毕,就会立即销毁新创建的包装对象;
引用类型和基本包装类型的主要区别就是对象的生存期;
自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁;
这意味着我们不能在运行时为基本类型值添加属性和方法;
@media
meta viewport
html标签中设置font-size: …px,然后下面的尺寸都用rem进行设计 62.5%
vm vh
function reArr (arr) { return arr.sort(() => { return Math.random() - 0.5; })}// console.log(reArr([2, 3, 1, 5]));function isReArr (n, reArr, arr) { var arr1 = [0, 0, 0, 0]; var length = arr.length; for (var i = 0; i < n; i++) { var arr2 = reArr(arr); for (var j = 0; j < length; j++) { arr1[j] += arr2[j]; } } arr1.forEach((item) => { return item / n; })}isReArr(500, reArr, [2, 3, 1, 5]);数组乱序function reArr (arr) { return arr.sort(() => { return Math.random() - 0.5; })}var list = [1,2,3,4,5,6,7,8,9,10];var newlist = [];for(var i=0;i<10;i++){ var num = Math.floor(Math.random()*list.length) ; newlist.push(list[num]); list.splice(num,1)}// forEach遍历,随机生成下标,交换位置function disorderArr(arr) { arr.forEach((e, i, a) => { let randomIndex = Math.floor(Math.random()*list.length) let temp = a[randomIndex] a[randomIndex] = a[i] a[i] = temp }) return arr }// 洗牌原理:从数组的最后位置开始,从前面随机一个位置,对两个数进行交换,直到循环完毕 function shuffleSort(arr) { let i = arr.length - 1 while(i>0) { let rIndex = Math.floor(Math.random()*i) let temp = arr[rIndex] arr[rIndex] = arr[i] arr[i] = temp i-- } return arr }
foo ();function foo () { console.log("foo1");}foo ();function foo () { console.log("foo2");}foo ();//foo2 foo2 foo2
var abc = function foo () {}console.log(typeof(foo));//undefinedconsole.log(typeof(foo()));//报错console.log(typeof(abc));//functionconsole.log(typeof(abc()));//undefined,因为函数没有返回值
PATCH方法是新引入的,是对PUT方法的补充,用来对已知资源进行局部更新
const d = new Date();const year = d.getFullYear();let month = (d.getMonth() + 1).toString().padStart(2, "0");let day = d.getDate().toString().padStart(2, "0");const time = `${year}-${month}-${day}`;console.log(time);const d = new Date();const year = d.getFullYear();let month = d.getMonth() + 1;let day = d.getDate();if (month.toString().length < 2) { month = "0" + month;}if (day.toString().length < 2) { day = "0" + day;}const time = year + "-" + month + "-" + day;console.log(time);
var temp=typeof 123;//>temp=‘number’
typeof typeof 123;//>typeof ‘number’==>‘string’
“object HTMLDivElement”,即 HTMLDivElement 对象
typescript ts是微软牵头主导的,主要来自C#
ts需要静态编译,它提供了强类型与更多面向对象的内容。
ts最终仍要编译为弱类型的js文件,基于对象的原生的js,再运行。故ts相较java/C#这样天生面向对象语言是有区别和局限的
TypeScript是一个应用程序级的JavaScript开发语言。(这也表示TypeScript比较牛逼,可以开发大型应用,或者说更适合开发大型应用)
TypeScript是JavaScript的超集,可以编译成纯JavaScript。这个和我们CSS离的Less或者Sass是很像的
TypeScript跨浏览器、跨操作系统、跨主机、且开源。由于最后他编译成了JavaScript所以只要能运行
TypeScript始于JavaScript,终于JavaScript。遵循JavaScript的语法和语义
TypeScript提供了类、模块和接口,更易于构建组件和维护。typescript与javascript关系
typescript是javascript的超集,即你可以在ts中使用原生js语法,扩展了javascript的语法。
typescript必须声明变量类型如:var message = “article”; //javascriptvar message:string = “article”; //typescript函数声明不同//javascriptfunction test(){return ‘article’}//typescript:需声明返回值类型function test():string{return ‘article’}基本数据类型不同:javascript:boolean类型、number类型、string类型、array类型、undefined、nulltypescript:除了上面类型外,还包含tuple类型(元组类型)、enum类型(枚举类型)、any类型(任意类型)ts增加的语法静态类型:有利于检查代码错误,运行前检查类型错误函数缺省参数值:类:模块:可以把声明、数据、函数和类封装在模块中接口:类型注解:通过类型注解来增加编译时静态类型检查
function arrSort(arr1, arr2) { var [i,j] = [0,0]; let newArr = []; while(i < arr1.length || j <arr2.length) { if (arr1[i] < arr2[j]) { newArr.push(arr1[i]); i++ } else if (arr1[i] > arr2[j]) { newArr.push(arr2[j]) j++ } else { //i或者j到头了,进行判断一下 if(arr1[i] !== undefined) newArr.push(arr1[i]); if(arr2[j] !== undefined) newArr.push(arr2[j]); i++; j++ } } return newArr}
数组性能我首先想到的就是从两方面,一是数组的迭代二是向数组中添加元素.
迭代的话是最普通的for循环效率最高,而且普通的for循环还可以继续优化;向数据中添加元素是用索引的方式添加元素最快,而且不同的浏览器各种方法效率有差异.但是利用索引添加元素最快无疑.
map和forEach对比:
1、map速度比foreach快
2、map会返回一个新数组,不对原数组产生影响,foreach不会产生新数组,foreach返回undefined
3、map因为返回数组所以可以链式操作,foreach不能
4, map它会返回⼀个新的数组,所以需要有 return 值,如果没有,会返回 undefined ;而foreach里用return不起作用,foreach不能用break,会直接报错。
. | $ ? * + ^ \ 转义需要用这个 ( ) [ ] { }
一张图片就是一个<img>标签,浏览器是否发起请求图片是根据<img>\的src属性,所以实现懒加载的关键就是,在图片没有进入可视区域时,先不给<img>的src赋值,这样浏览器就不会发送请求了,等到图片进入可视区域再给src赋值。
元素到浏览器顶部的距离 e.offsetTopwindow.innerHeight;//获取可视高度(屏幕高度)var scrollHeight = document.documentElement.scrollTop || document.body.scrollTop;//获取滚动的值if ((viewHeight + scrollHeight) > 元素到浏览器顶部的距离) { 设置一个定时器,制造懒加载的延迟加载的效果}
提高首屏的加载速度,提高用户体验,减小带宽
npm i vue-lazyload -s
import VueLazyload from ‘vue-lazyload’;
Vue.use(VueLazyload)或者
Vue.use(VueLazyload, {
error: ‘dist/error.png’,图片不存在时展示的错误图片
load: ‘dist/loading.gif或者.svg也行’,图片没加载出来时显示的样式
})还有其他options
< img v-load=“图片路径”/>
谷歌获取滚动的高度
document.documentElement.scrollTop
Y轴偏移量window.pageYOffset和上面是一样的
IE浏览器document.body.scrollTop
这三个总归有一个是能取到的
Object.myAssign = function (target, ...src) { for (let i = 0; i < src.length; i++) { if (src[i] !== null || src[i] !== undefined) { // 过滤掉源对象为null和undefined的情况 for (let key in src[i]) { // in运算符会查找原型对象上的可枚举属性,所以需要通过Object.prototype.hasOwnProperty方法过滤掉对象原型对象上的属性 if (src[i].hasOwnProperty(key)) { target[key] = src[i][key]; } } } } return target}
const p = Promise.resolve(1);p.then(console.log)p.then(console.log)//输出结果 1 1
var a = new Array(1, 1, 1);//[1 1 1]var a = new Array(5);//长度为5的空数组var a = [1, 1, 1]//报错
总的比较次数=(n-1)+(n-2)+.+1=n(n-1)/2
function MyIndexOf(str2,str1,n){//n为起始位置 let i;//循环变量 let len1=str1.length;//子串长度 let len2=str2.length;//父串长度 if(n==undefined ||n==null||n<=-1) {//没有传入起始位置时,从第一位开始 i=0; }else if(n>len2-1){//如果起始位置大于字符串最后一位,返回-1,不存在 return -1; }else{//如果不存在上述2种情况,从第n位开始 i=n; } if(len1>len2){//如果子串长大于父串,那么肯定不存在,返回-1 return -1; }else if(len1==len2){//如果相等,就对比2个字符串的内容 if(str1==str2){//如果内容相等,那么就是从第一位开始,返回0 return 0; }else{//长度相等,内容不相等,那么肯定不存在啦 return -1; } }else{ let str21=''; while(i<len2 - len1){ //拼合对比的父串,i到len1 str21=str2.substr(i,len1);//每次都拿出和子串长度一样的字符串去对比 if(str21==str1){ return i;//这里返回的就是第一次子串出现的位置,符合indexOf } if(i==len2 - len1){//如果循环到父串最后一位还是没有出现相等,那么就是-1不存在 return -1; } i++; } }}
阻止默认事件:
e.preventDefault()
e.returnValue = false (IE)
阻止冒泡:
e.stopPropagation()
e.cancelBubble = true (IE)
substr(start,length)是从起始索引号开始提取指定长度的字符串;
substring(start,stop)是提取字符串中两个指定索引号之间的字符;(跟Java中一样),数学上相当于提取 [start,stop) 之间的字符。
执行上下文有且只有三类,全局执行上下文,函数上下文,与eval上下文
https://www.cnblogs.com/echolun/p/11438363.html
<style>#target { width: 200px; height: 300px; margin: 40px; background-color: tomato;}</style> <div id="target"></div> <script>function addMask(elem, opacity) { opacity = opacity || 0.2; var rect = elem.getBoundingClientRect(); var style = getComputedStyle(elem, null); var mask = document.createElement('div'); mask.style.position = 'absolute'; var marginLeft = parseFloat(style.marginLeft); mask.style.left = (elem.offsetLeft - marginLeft) + 'px'; var marginTop = parseFloat(style.marginTop); mask.style.top = (elem.offsetTop - marginTop) + 'px'; mask.style.zIndex = 9999; mask.style.opacity = '' + opacity; mask.style.backgroundColor = '#000'; mask.style.width = (parseFloat(style.marginLeft) + parseFloat(style.marginRight) + rect.width) + 'px'; mask.style.height = (parseFloat(style.marginTop) + parseFloat(style.marginBottom) + rect.height) + 'px'; elem.parentNode.appendChild(mask);} var target = document.getElementById('target');addMask(target); target.addEventListener('click', function () { console.log('click');}, false);</script>
https://blog.csdn.net/CareChere/article/details/51312215
offsetLeft offsetWidth
https://blog.csdn.net/willard_cui/article/details/81712989
Promise.reject(2).catch(r = > { console.log('catch1');//捕获到错误,执行}).then(v => {//错误已经被捕获,后面的'then'都顺序执行,且 console.log('then1');}, r => { console.log('catch2');}).catch(r => { console.log('catch3');//前面没有未捕获的错误,未执行}).then(v => { console.log('then2');}, r => { console.log('catch4');})//catch1 then1 then2
//使用循环迭代方式实现function fb2(n){ var res1 = 1; var res2 = 1; var sum; var sum = res2; for(var i = 2;i < n;i ++){ sum = res1 + res2; res1 = res2; res2 = sum; } return sum;} //还可以用数组存数据的方式
https://www.cnblogs.com/shine1234/p/13356457.html
function countDivior(a,b) { if(b===0) { return a; } else { countDivior(b,a%b); }}
async mounted () { const data = await this.$axios.get("xxx"); this.list = data;}
function add (a) { return function (b) { return function (c) { return function (d) { return a + b + c + d } } }}-----------柯里化function add (...args) { return args.reduce((a, b) => a + b)//reduce里面可以放一个累加器(累加函数)进行累加效果}function currying (fn) { let args = [] return function _c (...newArgs) { if (newArgs.length) { // 合并参数 args = [...args, ...newArgs]; return _c } else { return fn.apply(this, args) } }}//回调函数是一个函数作为另一个函数的参数,在另一个函数内部执行let addCurry = currying(add)// 注意调用方式的变化console.log(addCurry(1)(2)(3)(4, 5)())
字符串1,2,3作为元素;0,1,2作为下标分别调用 parseInt 函数。即分别求出 parseInt(‘1’,0), parseInt(‘2’,1), parseInt(‘3’,2)的结果。第二个参数 区间范围介于2~36之间; 当参数为 0,parseInt() 会根据十进制来解析; 如果忽略该参数,默认的基数规则:如果 string 以 “0x” 开头,parseInt() 会把 string 的其余部分解析为十六进制的整数;parseInt(“0xf”) //15 …
[‘1’,‘2’,‘3’].map(parseInt)即
parseInt(‘1’,0);radix 为 0,parseInt() 会根据十进制来解析,所以结果为 1;
parseInt(‘2’,1);radix 为 1,超出区间范围,所以结果为 NaN;
parseInt(‘3’,2);radix 为 2,用2进制来解析,应以 0 和 1 开头,所以结果为 NaN。
由于二进制浮点数中0.1和0.2并不是十分精确
最简单的就是先把0.1和0.2换成别的数字(因为在js中只有这两个数相加有bug,例如:1.1+1.2不会有问题),所以先让0.1和0.2分别乘以10,求和之后再除以10 ,则不会有问题:(0.1*10+0.2*10)/10 ===0.3
或者parseFloat((0.1+0.2).toFixed(10)) ===0.3
parseFloat((0.1+0.2).toFixed(10))
toFixed(10)规定了小数的位数,0到20之间
str.trim() str.trimStart() str.trimEnd()String.prototype.trim = function(){ return this.replace(/^(\s*)|(\s*)$/g, '');}
function repeat (func, times, wait) { return function (content){ var count = 0; var interval = setInterval(function(){ count += 1; func(content); if(count === times){ clearInterval(interval); } }, wait); }} const repeatFunc = repeat(alert, 4, 3000)repeatFunc("hellworld");
will-change属性可以提前通知浏览器我们要对元素做什么动画,这样浏览器可以提前准备合适的优化设置。这样可以避免对页面响应速度有重要影响的昂贵成本。元素可以更快的被改变,渲染的也更快,这样页面可以快速更新,表现的更加流畅。
will-change: transform, opacity;
实现函数 keys(o, level),能够获取指定层次的键。示例:let o = { x: { a: 1, b: 2 }, y: 3, z: {c: 1, d: 2, p: {m: 3}}}keys(o, 1) // 返回 ['x', ‘y’, ‘z']keys(o, 2) // 返回 ['a', ‘b’, ‘c’, ‘d’ ‘p']keys(o, 3) // 返回 [‘m’]keys(o, 4) // 返回 []
function keys (o, level) {
if (level <= 1) {
return Object.keys(object);
}
const accumulatedKeys = [];
for (let value of Object.values(object)) {
if (typeof value === 'object') {
accumulatedKeys.push(...keys(value, level - 1));
}
}
return accumulatedKeys;
}
const obj = {a: 2};
const a = 1;
console.log(obj > a);
大于运算符的操作数可以是任意类型,单只有数字和字符串才能真正执行比较操作,其他类型都需要转换
如果操作数是对象,先使用valueOf()转换为原始值,如果结果不是原始值,再使用toString()转换
在对象转换为原始值之后,如果至少有一个操作数不是字符串,则两个操作数都转换为数字进行比较
原始值指基础类型值
({a: 2}) > 1就相当于 NaN > 1,应该是 false
function formatNum(str) { var newStr = ""; var count = 0; if(str.indexOf(".") === -1){ for(var i=str.length-1;i>=0;i--){ if(count % 3 == 0 && count != 0){ newStr = str.charAt(i) + "," + newStr; }else{ newStr = str.charAt(i) + newStr; } count++; str = newStr + ".00"; //自动补小数点后两位 console.log(str) } else { for(var i = str.indexOf(".")-1;i>=0;i--){ if(count % 3 == 0 && count != 0){ newStr = str.charAt(i) + "," + newStr; //碰到3的倍数则加上“,”号 }else{ newStr = str.charAt(i) + newStr; //逐个字符相接起来 } count++; } str = newStr + str.substring(str.indexOf(".")); console.log(str.toFixed(2));//保留两位小数 } }
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。说明:每次只能向下或者向右移动一步。
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。
解题思路
当前数的最小和 = 当前数 + min(左边数最小和,上边数最小和)
特例:第一列、第一行,需要单独处理
const minPathSum = grid => { const row = grid.length, col = grid[0].length; for (let i = 1; i < row; i++) { grid[i][0] += grid[i - 1][0]; } for (let j = 1; j < col; j++) { grid[0][j] += grid[0][j - 1]; } for (let i = 1; i < row; i++) { for (let j = 1; j < col; j++) { grid[i][j] += Math.min(grid[i - 1][j], grid[i][j - 1]); } } return grid[row - 1][col - 1];};
const a = new MySet([1,2,3,3])
a.add(4)
a.remove(4)
class Set { constructor() { this.items = {}; } add(value) { if (!this.has(value)) {//注意 this.items[value] = value; return true; } else { return false; } } remove(value) { if (this.has(value)) { delete this.items[value]; return true; } else { return false; } }}
把一段字符串中数字相关的放在数组中输出,如果是数字直接使用数字类型,其他都使用字符串类型输入:const str = '这是一篇文章:加快递费3.22X10^5,就开始的经费3673降低开jvjsldfjXDJKFLD发洛索洛芬2/3,是杜绝浪费0.12345,晋升的了客服-2344'输出结果:['3.22X10^5',3673,'2/3',0.12345,-2344]function getNum (str) { var arr = []; var reg = /X|\^|\/|\.|\d|\-/; while (reg.exec(str)) { var count = 0; var j = 0; for (var i = reg.exec(str) + 1; i < str.length; i++) { if (reg.test(str[i])) { count++; } else { arr[j] = str.splice(reg.exec(str), count); j++; } } } return arr;}match [ , , , ,]
splice(index,howmany,item1,.....,itemX)index使用负数可从数组结尾处规定位置,必填howmany要删除的项目数量,必填item1,.....,itemX 向数组添加的新项目,选填
动态作用域:函数内的成员是否可以被访问只有在运行的时候才能确定
function f(){ alert(x);}function f1(){ var x = 1; f();}function f2(){ var x = 2; f();}f1();//报错:x没有定义,说明JS没有动态作用域f2();
JS只有静态作用域lexical,也叫词法作用域或者闭包,在词法创建阶段就确定了相关的作用域。闭包:引用了自由变量的函数。
function f(){ var x = 100; function g(){ ... } g();}f();function f(){//f()创建的时候(浏览器解析的时候),给f添加一个看不到摸不着的成员[[scope]] //f.[[scope]] == window //f()被调用的时候会创建自己的一个词法环境f.le, f.le ->f.[[scope]]//在预处理阶段(上一行解释,f()刚刚被调用时),f.le{x = undefined, g(){...}},g.[[scope]] == f.le//在预处理阶段,无论g()是函数声明还是函数表达式创建的都会把g()加入到f.le中 var x = 100;//在执行阶段,f.le{x = 100, g(){...}} function g(){//在预处理阶段,g.[[scope]] == f.le ... } g();//g()在运行时,会创建自己的词法环境,g.le ->g.[[scope]] //综上形成一条链条 //g.le -> g.[[scope]] == f.le -> f.[[scope]] == window}f();
//Promise.allfunction promiseAll (promises) { if (!Array.isArray(promises)) { throw new Error ("promises must to be an array!!!"); } return new Promise (function (resolve, reject) { let promiseNum = promises.length; let resolvedCount = 0; let resolveValues = new Array(promiseNum); for (let i = 0; i < promiseNum; i++) { try{ promises[i].then(function (value) { resolveValues[i] = value; if (++resolvedCount === promiseNum) { resolve(resolveValues); } } } catch (error) { reject(error); } } })}//Promise.racefunction promiseRace(promise) { if (!Array.isArray (promises)) { throw new Error ("promises must be an array!!!"); } let resolved = false; return new Promise(function (resolve, reject) { try{ promises.forEach(p => p.then(data => { if (!resolved) { resolved = true; resolve (data); } }) ) } catch (error) { reject(error); } })}
var i = 1;var i = 2;var add = function() { var i = 0; return function(){ i++; console.log(i); }}();add();
代码回收规则如下:( 3个)
1.全局变量不会被回收。
2.局部变量会被回收,也就是函数一旦运行完以后,函数内部的东西都会被销毁。
3.只要被另外一个作用域所引用就不会被回收
有3个变量没有被回收,首先是全局变量中的i,第二行声明被忽略,赋值会覆盖掉第一行,因此只有1个。第二个是var add,这个变量也没有回收,他定义了一个匿名函数,并将它赋给了add。第三个就是闭包中的变量i,闭包中的局部变量是不会被回收的,因此是3个变量没有被回收。
function addCounter() { var counter = 0; const myFunction = function() { counter = counter + 1; return counter; } return myFunction;}const increment = addCounter();const c1 = increment();const c2 = increment();const c3 = increment();console.log(c1, c2, c3);//1, 2, 3-------------------------function fn(a) { console.log(a); var a = 2; function a() { console.log(a); }}fn(1);//f a() { console.log(a) }//函数的声明大于变量-----------------function fn1() { console.log(this);}fn1();//windowfn1.call({x: 100});//{x: 100}const fn2 = fn1.bind({x: 200});fn2();//{x: 200}------------当一个块级容器display:flex时,怎么设置使他的自己由顶部向下排列,再偏右排列flex-direction: column;justify-content: flex-start;align-items: flex-end;-------------------JavaScript中 window 对象的子对象不包含以下那个对象:documenthistoryselfmessage******--------------------------------------------------------------var string = 'string';var number = 0;var bool = true;console.log(number || string);//'string'console.log(number && string);//0console.log(bool || number);//trueconsole.log(bool && number);//0-----------------------------------------------function Foo() { console.log(this.location);}Foo();//当前窗口的Location对象---------------------javascript中的数字在计算机内存储为多少Byte?JavaScript内部,所有数字都是以64位浮点数形式储存,即使整数也是如此8 Byte = 64bit
// 优化性能,插⼊不会造成回流const fragment = document.createDocumentFragment();ul.appendChild(fragment);docunment.createElementdocument.documentElement
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。输入:nums = [-2,1,-3,4,-1,2,1,-5,4]输出:6解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。function maxNum(nums) { var arr = []; for (var i = 0; i < nums.length; i++) { var maxValue = nums[i]; var tempValue = nums[i]; for (var j = i + 1; j < nums.length; j++) { tempValue += nums[j]; if (tempValue > maxValue) { maxValue = tempValue; } } arr[i] = maxValue; } return Math.max(...arr);}var nums = [-2,1,-3,4,-1,2,1,-5,4];console.log(maxNum(nums));
setState本身并不是异步,只是因为react的性能优化机制体现为异步。在react的生命周期函数或者作用域下为异步,在原生的环境下为同步。
输入一个字符串,打印出该字符串中字符的所有排列。你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。示例:输入:s = "abc"输出:["abc","acb","bac","bca","cab","cba"]
我们将这个问题看作有 nn 个排列成一行的空位,我们需要从左往右依次填入题目给定的 nn 个字符,每个字符只能使用一次。首先可以想到穷举的算法,即从左往右每一个空位都依次尝试填入一个字符,看是否能填完这 nn 个空位,编程实现时,我们可以用「回溯法」来模拟这个过程。 定义递归函数 \texttt{backtrack}(i, \textit{perm})backtrack(i,perm) 表示当前排列为 \textit{perm}perm,下一个待填入的空位是第 ii 个空位(下标从 00 开始)。那么该递归函数分为两个情况: 如果 i=ni=n,说明我们已经填完了 nn 个空位,找到了一个可行的解,我们将 \textit{perm}perm 放入答案数组中,递归结束。 如果 i<ni<n,此时需要考虑第 ii 个空位填哪个字符。根据题目要求我们肯定不能填已经填过的字符,因此很容易想到的一个处理手段是我们定义一个标记数组 \textit{vis}vis 来标记已经填过的字符,那么在填第 ii 个字符的时候我们遍历题目给定的 nn 个字符,如果这个字符没有被标记过,我们就尝试填入,并将其标记,继续尝试填下一个空位,即调用函数 \texttt{backtrack}(i + 1, \textit{perm})backtrack(i+1,perm)。回溯时,我们需要要撤销该空位填的字符以及对该字符的标记,并继续向当前空位尝试填入其他没被标记过的字符。 但是该递归函数并没有满足「全排列不重复」的要求,在重复的字符较多的情况下,该递归函数会生成大量重复的排列。对于任意一个空位,如果存在重复的字符,该递归函数会将它们重复填上去并继续尝试导致最后答案的重复。 解决该问题的一种较为直观的思路是,我们首先生成所有的排列,然后进行去重。而另一种思路是我们通过修改递归函数,使得该递归函数只会生成不重复的序列。 具体地,我们只要在递归函数中设定一个规则,保证在填每一个空位的时候重复字符只会被填入一次。具体地,我们首先对原字符串排序,保证相同的字符都相邻,在递归函数中,我们限制每次填入的字符一定是这个字符所在重复字符集合中「从左往右第一个未被填入的字符」,即如下的判断条件: var permutation = function(s) { const rec = [], vis = []; const n = s.length; const arr = Array.from(s).sort(); const perm = []; const backtrack = (arr, i, n, perm) => { if (i === n) { rec.push(perm.toString()); return; } for (let j = 0; j < n; j++) { if (vis[j] || (j > 0 && !vis[j - 1] && arr[j - 1] === arr[j])) { continue; } vis[j] = true; perm.push(arr[j]); backtrack(arr, i + 1, n, perm); perm.pop(); vis[j] = false; } } backtrack(arr, 0, n, perm); const size = rec.length; const recArr = new Array(size).fill(0); for (let i = 0; i < size; i++) { recArr[i] = rec[i].split(',').join(''); } return recArr; };
function primeNubmer(n){ for(var i=2 ; i<n ; i++){ var a = true;//状态码判定是否打印 for(var j = 2; j <= Math.sqrt(i); j++){ //判断i能否被j整除 if(i%j == 0){ //能被整除则说明不是素数,修改布尔值为false a = false ; } } //打印素数 if(a){ document.writeln(i); } }}
一般涉及到大整数,都需要考虑通过数组或者字符串来模拟算术运算。我们通过数组来表示两个数字a、b(这里从左往右需要从个位数到最高位),这里的相乘只需要理解一点:a的每一位a[i]乘以b的每一位b[j],我们可以先将其放在结果中的result[i+j]中。这是模拟运算的过程。剩下的只需要将result中每一位大于9的进行进位即可。
function dazhenghsuAdd(str1,str2){ str1=str1.split('').reverse(); str2=str2.split('').reverse(); let result=[]; for(let i=0;i<str1.length;i++){ for(let j=0;j<str2.length;j++){ result[i+j]=result[i+j]||0;//如果result[i+j]是undefined则将其变为0 result[i+j]+=parseInt(str1[i])*parseInt(str2[j]); } } let temp; for(let k=0;k<result.length;k++){ if(result[k]>9){ temp=Math.floor(result[k]/10); result[k]=result[k]%10; result[k+1]=result[k+1]||0; result[k+1]+=temp; } } return result.reverse().join(''); }
1、form-data 将表单的数据组织成Key-Value形式,也可以上传文件
2、x-www-form-urlencoded 将表单内的数据转换为Key-Value
3、raw 传输txt,json xml,html的数据
4、binary 只可以上传二进制数据,用来上传文件,一次只能上传1个数据
for in可遍历原型链上扩展的属性,Object.keys() 只遍历自身属性
sort会改变原数组
三个并排的div宽度设置为33.3%,会出现问题?
理想中是显示在一行中,事实却是两行。
原因是因为: col元素 display: inline-block后,元素后面的换行符以及空格都会被算上宽度,所以会溢出。
两种解决方法:
line-height是干什么的?
line-height 行高,常见作用有二。
1.如果可能有换行,保证行与行之间距离合适。
2.居中。左侧字体14px,右侧字体18px。如果用一个行高将两部分框起来,可以保证左右两部分中心水平居中。
http1.0缓存弊端
HTTP/1.0缓存机制完全依赖时间,弊端显而易见,服务器、客户端的时钟不同步,文档的更新周期小于1s, 都会出现问题。
所以HTTP/1.1提倡的缓存机制是,对比文档的hash值,文档内容变,则hash变,用相对时间代替绝对时间
HTTP/1.1 继承 HTTP/1.0 所以HTTP/1.0的相关字段仍然有效,保留的这些字段就是为了兼容那些仅支持HTTP/1.0的客户端。 HTTP/1.1服务器不应该设置与1.0矛盾的过期策略, 1.1的服务器在没有文档hash值时,也可以使用If-Modified-Since进行判断文档过期。
新增字段:
Cache-Control最容易理解也是最常用的就是:
https的加密原理
HTTPS 没有采用单一的技术去实现,而是根据他们的特点,充分的将这些技术整合进去,以达到性能与安全最大化。这套整合的技术称之为 SSL(安全套接层),因此 HTTPS 并非是一项新的协议,它只是在 HTTP 上披了一层加密的外壳。
如何知道http的传输已经结束
1.Content-Length
2.Transfer-Encoding
https://www.dazhuanlan.com/cloud_zhao/topics/1414445
WebSocket是哪一层
websocket和http一样都是传输层协议、都是基于tcp应用层协议
tcp属于哪⼀层(1** 物理层 -> 2 数据链路层 -> 3 ⽹络层(ip)-> 4 传输层(tcp) -> 5 应⽤层(http))
闭包的原理和使用场景
实现柯里化
把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
好处:参数确认、提前确认、延迟执行
es6代理
http为什么要用长连接,一般用在什么场景中
设置Connection为keep-alive就算是长连接了,但要服务器和客户端都设置
长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况;
而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。
https://www.cnblogs.com/xifenglou/p/12888615.html
状态码 304 5xx
tcp连接过程中的状态考察
两端都为 CLOSED 状态
客户端便进⼊ SYN-SENT 状态
服务端进⼊ SYN-RECEIVED 状态
客户端进⼊ ESTABLISHED 状态
四次挥手,如果最后一个ack丢了会怎么样
1、当第四步的A发送的确认报文,B收到时,A会等待2MSL的时间后,连接彻底关闭。(因为B收到了,所以2MSL时间内B不会重发第三步的释放报文)
2、当第四步的A发送的确认报文,B没有收到时,B会继续发送第三步的释放报文,A收到后会继续发送第四步的确认报文(此时会重新启动2MSL计时器,重新等待2MSL时间),若在接下来的2MSL的时间内未收到B发送的第三步的释放报文,则意味着B已经收到了A的ack确认报文,连接彻底关闭
tcp三次握手详细过程
建⽴连接三次握⼿
在 TCP 协议中,主动发起请求的⼀端为客户端,被动连接的⼀端称为服务端。不管是客户端还是服务端, TCP 连接建⽴完后都能发送和接收数据,所以 TCP 也是⼀个全双⼯的协议。起初,两端都为 CLOSED 状态。在通信开始前,双⽅都会创建 TCB 。 服务器创建完TCB 后遍进⼊ LISTEN 状态,此时开始等待客户端发送数据
第⼀次握⼿
客户端向服务端发送连接请求报⽂段。该报⽂段中包含⾃身的数据通讯初始序号。请求发送后,客户端便进⼊ SYN-SENT 状态,x 表示客户端的数据通信初始序号。
第⼆次握⼿
服务端收到连接请求报⽂段后,如果同意连接,则会发送⼀个应答,该应答中也会包含⾃身的数据通讯初始序号,发送完成后便进⼊ SYN-RECEIVED 状态。
第三次握⼿
当客户端收到连接同意的应答后,还要向服务端发送⼀个确认报⽂。客户端发完这个报⽂段后便进⼊ ESTABLISHED 状态,服务端收到这个应答后也进⼊ESTABLISHED 状态,此时连接建⽴成功。
你是否有疑惑明明两次握⼿就可以建⽴起连接,为什么还需要第三次应答?
因为这是为了防⽌失效的连接请求报⽂段被服务端接收,从⽽产⽣错误
可以想象如下场景。客户端发送了⼀个连接请求 A,但是因为⽹络原因造成了超时,这时 TCP 会启动超时重传的机制再次发送⼀个连接请求 B。此时请求顺利到达服务端,服务端应答完就建⽴了请求。如果连接请求 A 在两端关闭后终于抵达了服务端,那么这时服务端会认为客户端⼜需要建⽴ TCP 连接,从⽽应答了该请求并进⼊ ESTABLISHED 状态。此时客户端其实是 CLOSED 状态,那么就会导致服务端⼀直等待,造成资源的浪费
insigned int 类型扩展长度
int 数据,内存就分配给它两个字节
https的建立连接过程
客户端发起https连接
服务端发送证书
客户端验证服务端发来的证书(验证证书、生成随机数、此随机数就是后面用的对称加密的私钥、生成握手信息)
服务端接收随机数加密的信息,并解密得到随机数,验证握手信息是否被篡改
客户端验证服务端发送回来的握手信息,完成握手
一个长度为一百万的数组中,有超过一半的数都是某一个值,求这个值
1.定义一个辅助数组 zero ,里面全是0;
2.循环输入的数组 arr ,将 arr 每个位置的值(arr[i])对应到辅助数组zero里的每个位置,使之++。
即 如果arr[1]的值是2,就对应到zero[2],使zero[2]的值++;……;如果arr[5]的值又是2,就再对应到zero[2],使zero[2]的值++;
3.循环辅助数组 zero,将其中的数与 arr长度的一半作比较,如果大于则输出该数的位置。即如果 arr.length/2 == 3,zero[3] == 4,则输出3。
function arrCount(arr){ var count = arr.length/2; var zero = new Array(Math.floor(count); var res = 0; if (arr.length == 0) { console.log("This arr is null!"); return; } for(let i = 0; i < arr.length; i++){ zero[arr[i]]++; if (zero[arr[i]] >= count) { return arr[i]; } }}
页面加载完成有两种事件
load是当页面所有资源全部加载完成后(包括DOM文档树,css文件,js文件,图片资源等)执行一个函数
问题:如果图片资源较多,加载时间较长,onload后等待执行的函数需要等待较长时间,所以一些效果可能受到影响
$(document).ready()是当DOM文档树加载完成后执行一个函数 (不包含图片,css等)所以会比load较快执行
在原生的js中不包括ready()这个方法,只有load方法就是onload事件
(ESNext:ES6转JavaScript)
array.filter((item, index) => {}
<span style="font-size:18px;"><xml><list><item><id>12</id><name>张三</name></item><item><id>13</id><name>李四</name></item></list></xml></span>
答案:
<span style=“font-size:18px;”>var list = [{“id”:“12”,“name”:“张三”},{“id”:“13”,“name”:“李四”}];</span>
https://blog.csdn.net/weixin_45259626/article/details/106078006
https://www.cnblogs.com/mahmud/p/10492189.html
https://blog.csdn.net/qq_27852041/article/details/87855130
CSS 模块化的实现方式
BEM 命名规范
BEM 的意思就是块(block)、元素(element)、修饰符(modifier)。是由 Yandex 团队提出的一种前端命名方法论。这种巧妙的命名方法让你的 css 类对其他开发者来说更加透明而且更有意义。
scss,@import ‘./css/base.css’;/页面基础样式/
less支持了模块化,可以@import ‘xxx.less’的形式导入其他less文件实现模块化。
css也可以用@import ‘xxx.css’方式实现模块化,所有页面只引用一个style.css。
这样可以http请求的消耗,同样方便合作开发,后期新增和删除模块只需修改这一个文件即可。
//加减乘除//加法function accAdd(arg1,arg2){ var r1,r2,m; try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0}; try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0}; m=Math.pow(10,Math.max(r1,r2)); return (arg1*m+arg2*m)/m;}//减法function accSubtr(arg1,arg2){ var r1,r2,m,n; try{r1=arg1.toString().split(".")[1].length;}catch(e){r1=0;} try{r2=arg2.toString().split(".")[1].length;}catch(e){r2=0;} m=Math.pow(10,Math.max(r1,r2)); //动态控制精度长度 n=(r1>=r2)?r1:r2; return ((arg1*m-arg2*m)/m).toFixed(n);} //乘法function accMul(arg1,arg2){ var m=0,s1=arg1.toString(),s2=arg2.toString(); try{m+=s1.split(".")[1].length}catch(e){}; try{m+=s2.split(".")[1].length}catch(e){}; return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m);}//除法function accDivCoupon(arg1,arg2){ var t1=0,t2=0,r1,r2; try{t1=arg1.toString().split(".")[1].length;}catch(e){} try{t2=arg2.toString().split(".")[1].length;}catch(e){} with(Math){ r1=Number(arg1.toString().replace(".","")); r2=Number(arg2.toString().replace(".","")); return (r1/r2)*pow(10,t2-t1); }}
function Promise(exector) { let self = this; //status表示一种状态 let status = "pending"; let value = undefined; let reason = undefined; //成功执行 function resolve(value) { if (status == 'pending') { self.value = value; self.status = "resolve"; } } //执行失败 function reject(reason) { if (status == 'pending') { self.reason = reason; self.status = "reject" } } //对异常操作 try { exector(resolve, reject) } catch (e) { reject(e) } //设置promise的then方法 Promise.prototype.then = function(reject, resolve) { let self = this; if (self.status == 'resolve') { reject(self.value) } if (self.status == 'reject') { resolve(self.reason) } } //new 一个promise 进行测试 let promise = new Promise((reject, resolve) => { resolve("return resolve"); }); promise.then(data => { console.log(`success${data}`); }, err => { console.log(`err${err}`); })}
//直接遍历,找到最小值。像选择排序一样,找到最小值索引,找到最小值//利用二分查找。如果中间元素值>最后一个元素值,说明最小值右半区间,如果中间元素<最后一个元素区间,说明最小值在左半区间,如果相等说明有相同元素,需要将判断区间往前缩一下,继续判断,不断循环,当二分查找的的左右区间相等了,就说明找到最小值了。function minNumberINRotateArray (rotateArray) { var len = rotateArray.length; if (len = 0) {return 0;} var left = 0; var right = len - 1; while (left < right) { var mid = Math.floor(len / 2); if (rotateArray[mid] > rotateArray[right]) { left = mid + 1; }else if (rotateArray[mid] < rotateArray[right]) { right=mid; }else { right=right-1; } } } return rotateArray[left];}
function formatColor(str) { const newstr = str.replace(/(rgb\()|(\))/g, '') const arr = newstr.split(',') let res = '#' for(var val of arr){ res += fillZero(switchNumToSixteen(parseInt(val))) } return res} function switchNumToSixteen(num) { return num.toString(16)//转换为16进制} function fillZero(str) { if(parseInt(str, 16) < 16) {//转换为16进制 return '0' + str } return str}
输入描述: namespace({a: {test: 1, b: 2}}, 'a.b.c.d') 输出描述: {a: {test: 1, b: {c: {d: {}}}}} 理解题意 命名空间 命名空间是一种代码封装技术,代码中的每个成员,都是自己的活动空间,彼此互不干扰。 首先理解题意,namespace($1, $2)函数中第一个参数是现有命名空间中的对象,而第二个参数是需要此空间实现的结构(即对象的包含关系),可知是a包含b包含c包含d; 解题思路 首先因为题目所要求创建的空间是顺序的,所以直接通过循环,将其一个个创建即可。 当空间中包含对象时(如a:{test:1})则保留此对象;当包含内容不是对象时(如b:2),则将其设置为一个空对象。如果不包含此空间名,则在其上一级空间中创建一个空对象。 function namespace(oNamespace, sPackage) { var package = sPackage.split('.'); var obj = oNamespace; for (var i = 0; i < package.length; ++i) { if (typeof obj[package[i]] !== 'object') { obj[package[i]] = {}; } obj = obj[package[i]]; } return oNamespace; }
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。
思路:
利用路径标记的方式,采用一维数组标记是否相连:若城市 i 与城市 j 相连,则与城市 j 相连的其它城市均与城市 i 相连。
通过dfs方式可以搜索全部的相连城市,并根据搜索的路径确定当前城市是否为当前类别。
TCP 是全双⼯的,在断开连接时两端都需要发送 FIN 和 ACK 。
第⼀次握⼿
若客户端 A 认为数据发送完成,则它需要向服务端 B 发送连接释放请求。
第⼆次握⼿
B 收到连接释放请求后,会告诉应⽤层要释放 TCP 链接。然后会发送 ACK包,并进⼊ CLOSE_WAIT 状态,表示 A 到 B 的连接已经释放,不接收 A 发的数据了。但是因为 TCP 连接时双向的,所以 B 仍旧可以发送数据给 A。
第三次握⼿
如果此时还有没发完的数据会继续发送,完毕后会向 A 发送连接释放请求,然后 B 便进⼊ LAST-ACK 状态。PS:通过延迟确认的技术(通常有时间限制,否则对⽅会误认为需要重传),可以将第⼆次和第三次握⼿合并,延迟 ACK 包的发送。
第四次握⼿
A 收到释放请求后,向 B 发送确认应答,此时 A 进⼊ TIME-WAIT 状态。该状态会持续2MSL(最⼤段⽣存期,指报⽂段在⽹络中⽣存的时间,超时会被抛弃) 时间,若该时间段内没有 B 的重发请求的话,就进⼊ CLOSED 状态。当 B 收到确认应答后,也便进⼊CLOSED 状态。
Form表单可以跨域是因为要保持兼容性,当请求到另一个域名后,原页面得脚本无法获取新页面中得内容,提交的form表单数据不需要返回,所以浏览器认为是安全得行为,所以浏览器不会阻止form表单跨域,而ajax我们需要返回的数据,浏览器认为不安全,所以会阻止这个请求行为。
onfocus onblur onkeydown onkeyup onclick
onchange 当input失去焦点并且它的value值发生变化时触发
onselect 当input里的内容文本被选中后执行一段,只要选择了就会触发,不是非得全部选中
oninput 当input的value值发生变化时就会触发,不用等到失去焦点(与onchange的区别)
mixin ⽤于全局混⼊,会影响到每个组件实例,通常插件都是这样做初始化的,虽然⽂档不建议我们在应⽤中直接使⽤ mixin ,但是如果不滥⽤的话也是很有帮助的,⽐如可以全局混⼊封装好的 ajax 或者⼀些⼯具函数等等。
mixins 应该是我们最常使⽤的扩展组件的⽅式了。如果多个组件中有相同的业务逻辑,就可以将这些逻辑剥离出来,通过 mixins 混⼊代码,⽐如上拉下拉加载数据这种逻辑等等。
另外需要注意的是 mixins 混⼊的钩⼦函数会先于组件内的钩⼦函数执⾏,并且在遇到同名选项的时候也会有选择性的进⾏合并。
当然⼯⼚模式并不仅仅是⽤来 new 出实例。
可以想象⼀个场景。假设有⼀份很复杂的代码需要⽤户去调⽤,但是⽤户并不关⼼这些复杂的代码,只需要你提供给我⼀个接⼝去调⽤,⽤户只负责传递需要的参数,⾄于这些参数怎么使⽤,内部有什么逻辑是不关⼼的,只需要你最后返回我⼀个实例。这个构造过程就是⼯⼚。
⼯⼚起到的作⽤就是隐藏了创建实例的复杂度,只需要提供⼀个接⼝,简单清晰。
在 Vue 源码中,你也可以看到⼯⼚模式的使⽤,⽐如创建异步组件
function repeatStr(str) {
const len = 20;
const n = Math.ceil(len / str.length);
return str.repeat(n).substr(0, len);
}
function shieldStr(str) {
const arr = str.split("@");
const str1 = "*".repeat(arr[0].length);
const str2 = arr[1];
return `${str1}@${str2}`;
}
在实际开发中,为什么我们要把“类数组”转换为“真正的数组”,其目的是什么?
主要是为了使得类数组也能使用真正数组的各种方法,比如push()、slice()等。
const person = { name: "Jack", age: 24};const result = Object.assign({}, person);result.name = "Lucy";console.log(result.name);console.log(person.name);//下面有一段代码,其运行结果是://"Lucy", "Jack"const person = { name: { first: "Jack", last: "Mo" }, age: 24};const result = Object.assign({}, person);result.name.first = "Lucy";console.log(result.name.first);console.log(person.name.first);//"Lucy", "Lucy"
//递归。树的深度=左子树的深度和右子树深度中最大者+1function TreeDepth(pRoot){ if(pRoot === null) return 0; var left = TreeDepth(pRoot.left); var right = TreeDepth(pRoot.right); return Math.max(left,right)+1;}
//1. 可以通过 instanceofvar set = new Set();console.log(set instanceof Set);//2. 构造函数 constructorconsole.log(set.constructor == Set);//3. Object.prototype.toString.call()var set = new Set();console.log(Object.prototype.toString.call(set) == "[object Set]");//4. isPrototypeOfvar set = new Set();console.log(Set.prototype.isPrototypeOf(set));
//输入:nums = [-1,0,1,2,-1,-4]//输出:[[-1,-1,2],[-1,0,1]]
1 合理的 title 、 description 、 keywords 。
语义化代码让搜索引擎容易理解⽹⻚,重要内容 HTML 代码放在最前:搜索引擎抓取 HTML 顺序是从上到下,有的搜索引擎对抓取⻓度有限制,保证重要内容⼀定会被抓取重要内容不要⽤ js 输出:爬⾍不会执⾏js获取内容
3 少⽤ iframe 。搜索引擎不会抓取 iframe 中的内容
4 ⾮装饰性图⽚必须加 alt。
5 提⾼⽹站速度。⽹站速度是搜索引擎排序的⼀个重要指标
在⽤户没有与因特⽹连接时,可以正常访问站点或应⽤,在⽤户与因特⽹连接时,更新⽤户机器上的缓存⽂件
原理: HTML5 的离线存储是基于⼀个新建的 .appcache ⽂件的缓存机制(不是存储技术),通过这个⽂件上的解析清单离线存储资源,这些资源就会像 cookie ⼀样被存储了下来。之后当⽹络在处于离线状态下时,浏览器会通过被离线存储的数据进⾏⻚⾯展示
如何使⽤:
⻚⾯头部像下⾯⼀样加⼊⼀个 manifest 的属性;在 cache.manifest ⽂件的编写离线存储的资源;在离线状态时,操作 window.applicationCache 进⾏需求实现
在线的情况下,浏览器发现 html 头部有 manifest 属性,它会请求 manifest ⽂件,如果是第⼀次访问 app ,那么浏览器就会根据manifest⽂件的内容下载相应的资源并且进⾏离线存储。如果已经访问过 app 并且资源已经离线存储了,那么浏览器就会使⽤离线的资源加载⻚⾯,然后浏览器会对⽐新的 manifest ⽂件与旧的 manifest ⽂件,如果⽂件没有发⽣改变,就不做任何操作,如果⽂件改变了,那么就会重新下载⽂件中的资源并进⾏离线存储。
离线的情况下,浏览器就直接使⽤离线存储的资源。
class :为元素设置类标识
data-* : 为元素增加⾃定义属性
draggable : 设置元素是否可拖拽
id : 元素 id ,⽂档内唯⼀
lang : 元素内容的的语⾔
style : ⾏内 css 样式
title : 元素相关的建议信息
HTML5 不基于 SGML ,因此不需要对 DTD 进⾏引⽤,但是需要 doctype 来规范浏览器的⾏为
⽽ HTML4.01 基于 SGML ,所以需要对 DTD 进⾏引⽤,才能告知浏览器⽂档所使⽤的⽂档类型
svg
border-radius
局部处理
mate 标签中的 viewport 属性 , initial-scale 设置为 1
rem 按照设计稿标准⾛,外加利⽤ transfrome 的 scale(0.5) 缩⼩⼀倍即可;
全局处理
mate 标签中的 viewport 属性 , initial-scale 设置为 0.5
rem 按照设计稿标准⾛即可
改版的时候更⽅便,只要改 css ⽂件。
⻚⾯加载速度更快、结构化清晰、⻚⾯显示简洁。
表现与结构相分离。
易于优化( seo )搜索引擎更友好,排名更容易靠前。
HTTP协议由两部分程序实现:一个客户端程序和一个服务器程序,它们运行在不同的端系统当中,通过交换HTTP报文进行会话。
在一个会话中,跟踪请求之间的数据成为会话跟踪。
(一)应用隐藏域进行会话跟踪(隐藏 input)
利用HTML中的隐藏域,在网页表单内填写客户端的信息。这些信息会随客户端的请求信息一起传送给服务器,服务器通过获取的这些信息来进行会话跟踪。
隐藏域的HTML标签如下:
<input type=“hidden” name=“隐藏域名称” value=“默认值”>
应用隐藏域的请求信息在浏览器页面是看不到的,但是查看源代码的话是可以看到客户端的请求信息的,所以这种方式显然是不安全的,会导致信息泄露。
(二)SSL会话(Secure Socket Layer)
安全套接字(Secure Socket Layer,SSL)协议是Web浏览器与Web服务器之间安全交换信息的协议,提供两个基本的安全服务:鉴别与保密。在SSL中会使用密钥交换算法交换密钥;使用密钥对数据进行加密;使用散列算法对数据的完整性进行验证,使用数字证书证明自己的身份。
(三)Cookies
Cookie是由服务器端生成,发送给浏览器,浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie名称和值可以由服务器端开发自己定义,这样服务器可以知道该用户是否合法用户以及是否需要重新登录等。
服务器可以利用Cookies包含信息的任意性来筛选并经常性维护这些信息,以判断在HTTP传输中的状态。Cookies最典型的应用是判定注册用户是否已经登录网站,用户可能会得到提示,是否在下一次进入此网站时保留用户信息以便简化登录手续,这样就实现了对客户的追踪。
(四)URL重写
URL重写就是首先获得一个进入的URL请求然后把它重新写成网站可以处理的另一个URL的过程。举个例子来说,如果通过浏览器进来的URL是“UserProfile.aspx?ID=1”那么它可以被重写成 “UserProfile/1.aspx”,这样的URL,这样的网址可以更好的被网站所阅读。
如果浏览器不支持Cookie或用户阻止了所有Cookie,可以把会话ID附加在HTML页面中所有的URL上,这些页面作为响应发送给客户。这样,当用户单击URL时,会话ID被自动作为请求行的一部分而不是作为头行发送回服务器。这种方法称为URL重写。
(五)ip 地址
link属于html标签。@import在css中使用表示导入外部样式表;
页面被加载的时,link会同时被加载,而@import引用的CSS会等到页面被加载完再加载;
import只在IE5以上才能识别,而link是HTML标签,无兼容问题;
link方式的样式的权重高于@import的权重;
link 支持使用javascript改变样式 (document.styleSheets),后者不可
总体来说: link 优于 @import
Flash Of Unstyled Content :⽤户定义样式表加载之前浏览器使⽤默认样式显示⽂档,⽤户样式加载渲染之后再从新显示⽂档,造成⻚⾯闪烁。
解决⽅法:把样式表放到⽂档的 <head>
偶数字号相对更容易和 web 设计的其他部分构成⽐例关系
均具有“变量”、“混合”、“嵌套”、“继承”、“颜⾊混合”五⼤基本特性;
Scss 和 LESS 语法较为严谨, LESS 要求⼀定要使⽤⼤括号“{}”, Scss 和 Stylus 可以通过缩进表示层次与嵌套关系
Scss ⽆全局变量的概念, LESS 和 Stylus 有类似于其它语⾔的作⽤域概念
Sass 是基于 Ruby 语⾔的,⽽ LESS 和 Stylus 可以基于 NodeJS NPM 下载相应库后进⾏编译;
可以直观的理解为:它就是⼀个平台。PostCSS 提供了⼀个解析器,它能够将 CSS 解析成抽象语法树
通过在 PostCSS 这个平台上,我们能够开发⼀些插件,来处理我们的 CSS ,⽐如热⻔的: autoprefixer
postcss 可以对sass处理过后的 css 再处理 最常⻅的就是 autoprefixer
伪类表状态;伪元素是真的有元素
前者单冒号,后者双冒号
知道是要⽤ CSS3 。使⽤ animation 动画实现⼀个简单的幻灯⽚效果
.ani{ width:480px; height:320px; margin:50px auto; overflow: hidden; box-shadow:0 0 5px rgba(0,0,0,1); background-size: cover; background-position: center; -webkit-animation-name: "loops"; -webkit-animation-duration: 20s; -webkit-animation-iteration-count: infinite;}@-webkit-keyframes "loops" { 0% { background:url(http:// } 25% { background:url(http:// } 50% { background:url(http:// } 75% { background:url(http:// } 100% { background:url(http:// }}
硬件加速是指通过创建独⽴的复合图层,让GPU来渲染这个图层,从⽽提⾼性能,⼀般触发硬件加速的 CSS 属性有 transform 、 opacity 、 filter ,为了避免2D动画,在开始和结束的时候的 repaint 操作,⼀般使⽤tranform:translateZ(0)
transform:scale() 这个属性只可以缩放可以定义宽⾼的元素,⽽⾏内元素是没有宽⾼的,我们可以加上⼀个 display:inline-block ;
JSON 相对 于XML 来讲,数据的体积⼩,传递的速度更快些。
JSON 与 JavaScript 的交互更加⽅便,更容易解析处理,更好的数据交互
JSON 对数据的描述性⽐ XML 较差
JSON 的速度要远远快于 XML
offsetWidth/offsetHeight 返回值包含content + padding + border,效果与e.getBoundingClientRect()相同
clientWidth/clientHeight 返回值只包含content + padding,如果有滚动条,也不包含滚动条
scrollWidth/scrollHeight 返回值包含content + padding + 溢出内容的尺⼨
ele.scrollTop = 被卷去的上侧距离
ele.scrollHeight = 自身实际的高度(不包括边框)
特点:
它是⼀个 Javascript 运⾏环境
依赖于 Chrome V8 引擎进⾏代码解释
事件驱动
⾮阻塞 I/O
单进程,单线程
优点:
⾼并发(最重要的优点)
缺点:
只⽀持单核 CPU ,不能充分利⽤ CPU
可靠性低,⼀旦代码某个环节崩溃,整个系统都崩溃
它的功能是把对应的字符串解析成 JS 代码并运⾏应该避免使⽤ eval ,不安全,⾮常耗性能( 2 次,⼀次解析成 js 语句,⼀次执⾏)
由 JSON 字符串转换为JSON对象的时候可以⽤ eval
var obj =eval(’(’+ str +’)’);
var obj = str.parseJSON();
var obj = JSON.parse(str);
JSON 对象转换为JSON字符串
var last=obj.toJSONString();
var last=JSON.stringify(obj);
同步:浏览器访问服务器请求,⽤户看得到⻚⾯刷新,重新发请求,等请求完,⻚⾯刷新,新内容出现,⽤户看到新内容,进⾏下⼀步操作
异步:浏览器访问服务器请求,⽤户正常操作,浏览器后端进⾏请求。等请求完,⻚⾯不刷新,新内容也会出现,⽤户看到新内容
变量必须声明后再使⽤
函数的参数不能有同名属性,否则报错
不能使⽤ with 语句
禁⽌ this 指向全局对象
⾯向过程就是分析出解决问题所需要的步骤,然后⽤函数把这些步骤⼀步⼀步实现,使⽤的时候⼀个⼀个依次调⽤就可以了
⾯向对象是把构成问题事务分解成各个对象,建⽴对象的⽬的不是为了完成⼀个步骤,⽽是为了描叙某个事物在整个解决问题的步骤中的⾏为
⾯向对象是以功能来划分问题,⽽不是步骤
函数体内的 this 对象,就是定义时所在的对象,⽽不是使⽤时所在的对象
不可以当作构造函数,也就是说,不可以使⽤ new 命令,否则会抛出⼀个错误
不可以使⽤ arguments 对象,该对象在函数体内不存在。如果要⽤,可以⽤ Rest 参数代替
不可以使⽤ yield 命令,因此箭头函数不能⽤作 Generator 函数
CSS3 的动画的优点:
在性能上会稍微好⼀些,浏览器会对 CSS3 的动画做⼀些优化
代码相对简单
缺点:
在动画控制上不够灵活
兼容性不好
JavaScript 的动画正好弥补了这两个缺点,控制能⼒很强,可以单帧的控制、变换,同时写得好完全可以兼容 IE6 ,并且功能强⼤。对于⼀些复杂控制的动画,使⽤javascript 会⽐较靠谱。⽽在实现⼀些⼩的交互动效的时候,就多考虑考虑 CSS 吧
gulp 是前端开发过程中⼀种基于流的代码构建⼯具,是⾃动化项⽬的构建利器;它不仅能对⽹站资源进⾏优化,⽽且在开发过程中很多重复的任务能够使⽤正确的⼯具⾃动完成
Gulp的特点:
易于使⽤:通过代码优于配置的策略,gulp 让简单的任务简单,复杂的任务可管理
构建快速: 利⽤ Node.js 流的威⼒,你可以快速构建项⽬并减少频繁的 IO 操作
易于学习
var arr = [1,2,3,4,5,6,7,8,9,10];arr.sort(function(){ return Math.random() - 0.5;})console.log(arr);
var domList = document.getElementsByTagName(‘input’)var checkBoxList = [];var len = domList.length; //缓存到局部变量while (len--) { //使⽤while的效率会⽐for循环更⾼ if (domList[len].type == ‘checkbox’) { checkBoxList.push(domList[len]); }}
caller 是返回⼀个对函数的引⽤,该函数调⽤了当前函数;
callee 是返回正在被执⾏的 function 函数,也就是所指定的 function 对象的正⽂
addEventListener() 是符合W3C规范的标准⽅法; attachEvent() 是IE低版本的⾮标准⽅法
addEventListener() ⽀持事件冒泡和事件捕获; ⽽ attachEvent() 只⽀持事件冒泡
addEventListener() 的第⼀个参数中,事件类型不需要添加 on ; attachEvent() 需要添加 ‘on’
如果为同⼀个元素绑定多个事件, addEventListener() 会按照事件绑定的顺序依次执⾏,attachEvent() 会按照事件绑定的顺序倒序执⾏
全局变量
Infinity 代表正的⽆穷⼤的数值。
NaN 指示某个值是不是数字值。
undefined 指示未定义的值。
全局函数
个人记忆方法:6(编码相关)+ 2(数据处理)+ 4(数字相关)+ 1(特殊)
编码相关:
escape()、unescape()、encodeURI()、decodeURI()、
encodeURIComponent()、decodeURIComponent()
数据处理:
Number()、String()
数字相关:
isFinite()、isNaN()、parseFloat()、parseInt()
特殊:
eval()
JSON.stringify(obj)==JSON.stringify(obj2);//true
浅拷⻉
Object.assign 或者 展开运算符
深拷⻉
可以通过 JSON.parse(JSON.stringify(object)) 来解决,该⽅法也是有局限性的,会忽略 undefined
但是该⽅法也是有局限性的:
会忽略 undefined
会忽略 symbol
不能序列化函数
不能解决循环引⽤的对象
防抖动是将多次执⾏变为最后⼀次执⾏,节流是将多次执⾏变成每隔⼀段时间执⾏
在⽣成执⾏环境时,会有两个阶段。第⼀个阶段是创建的阶段,JS 解释器会找出需要提升的变量和函数,并且给他们提前在内存中开辟好空间,函数的话会将整个函数存⼊内存中,变量只声明并且赋值为 undefined ,所以在第⼆个阶段,也就是代码执⾏阶段,我们可以直接提前使⽤在提升的过程中,相同的函数会覆盖上⼀个函数,并且函数优先于变量提升
function GetBytes(str){
var len = str.length;
var bytes = len;
for(var i=0; i<len; i++){
if (str.charCodeAt(i) > 255) bytes++;
}
return bytes;
}
bind 的作⽤与 call 和 apply 相同,区别是 call 和 apply 是⽴即调⽤函数,⽽bind 是返回了⼀个函数,需要调⽤的时候再执⾏。 ⼀个简单的 bind 函数实现如下
Function.prototype.bind = function(ctx) {
var fn = this;
return function() {
fn.apply(ctx, arguments);
};
};
//可⾏的⽅法⼀:
function log(msg) {
console.log(msg);
}
log("hello world!") // hello world!
//如果要传⼊多个参数呢?显然上⾯的⽅法不能满⾜要求,所以更好的⽅法是:
function log(){
console.log.apply(console, arguments);
}
使⽤⾃带接trim() ,考虑兼容性:
if (!String.prototype.trim) { String.prototype.trim = function() { return this.replace(/^\s+/, "").replace(/\s+$/,""); }}var str = " \t\n test string ".trim();alert(str == "test string"); // alerts "true"
for(var i=0;i<10;i++){ (function(j){ setTimeout(function(){ console.log(i+1) },i*1000) })(i)}
function run(input) { if (typeof input !== 'string') return false; return input.split('').reverse().join('') === input;}
多台服务器共同协作,不让其中某⼀台或⼏台超额⼯作,发挥服务器的最⼤作⽤
http 重定向负载均衡:调度者根据策略选择服务器以302响应请求,缺点只有第⼀次有效果,后续操作维持在该服务器 dns负载均衡:解析域名时,访问多个 ip 服务器中的⼀个(可监控性较弱)
反向代理负载均衡:访问统⼀的服务器,由服务器进⾏调度访问实际的某个服务器,对统⼀的服务器要求⼤,性能受到服务器群的数量
内容分发⽹络,基本思路是尽可能避开互联⽹上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。
后端每次路由请求都是重新访问服务器
前端路由实际上只是 JS 根据 URL 来操作 DOM 元素,根据每个⻚⾯需要的去服务端请求数据,返回数据后和模板进⾏组合
⽹站重构:在不改变外部⾏为的前提下,简化结构、添加可读性,⽽在⽹站前端保持⼀致的⾏为。也就是说是在不改变UI的情况下,对⽹站进⾏优化, 在扩展的同时保持⼀致的UI
对于传统的⽹站来说重构通常是:
表格( table )布局改为 DIV+CSS
使⽹站前端兼容于现代浏览器(针对于不合规范的 CSS 、如对IE6有效的)
对于移动平台的优化
针对于 SEO 进⾏优化
⾼复⽤低耦合,这样⽂件⼩,好维护,⽽且好扩展。
具有可⽤性、健壮性、可靠性、宽容性等特点
// [] 转成 true,然后取反变成 false
[] == false
[] == ToNumber(false)
[] == 0
ToPrimitive([]) == 0
// [].toString() -> ‘’
‘’ == 0
0 == 0 // -> true
如果⼀个节点中的⼦节点是动态⽣成的,那么⼦节点需要注册事件的话应该注册在⽗节点上
事件代理的⽅式相对于直接给⽬标注册事件来说,有以下优点
节省内存
不需要给⼦节点注销事件
当 Event loop 执⾏完 Microtasks 后,会判断 document 是否需要更新。因为浏览器是 60Hz 的刷新率,每 16ms 才会更新⼀次。然后判断是否有 resize 或者 scroll ,有的话会去触发事件,所以 resize 和scroll 事件也是⾄少 16ms 才会触发⼀次,并且⾃带节流功能。
判断是否触发了 media query
更新动画并且发送事件
判断是否有全屏操作事件
执⾏ requestAnimationFrame 回调
执⾏ IntersectionObserver 回调,该⽅法⽤于判断元素是否可⻅,可以⽤于懒加载上,但是兼容性不好
更新界⾯
以上就是⼀帧中可能会做的事情。如果在⼀帧中有空闲时间,就会去执⾏requestIdleCallback 回调
+‘b’ NaN
在开发中,可能会遇到这样的情况。有些资源不需要⻢上⽤到,但是希望尽早获取,这时候就可以使⽤预加载
预加载其实是声明式的 fetch ,强制浏览器请求资源,并且不会阻塞 onload 事件
预加载可以⼀定程度上降低⾸屏的加载时间,因为可以将⼀些不影响⾸屏但重要的⽂件延后加载,唯⼀缺点就是兼容性不好
可以通过预渲染将下载的⽂件预先在后台渲染,可以使⽤以下代码开启预渲染
预渲染虽然可以提⾼⻚⾯的加载速度,但是要确保该⻚⾯百分百会被⽤户在之后打开,否则就⽩⽩浪费资源去渲染
<link rel = "prerender" href = "http://poetries.com" />
懒执⾏就是将某些逻辑延迟到使⽤时再计算。该技术可以⽤于⾸屏优化,对于某些耗时逻辑并不需要在⾸屏就使⽤的,就可以使⽤懒执⾏。懒执⾏需要唤醒,⼀般可以通过定时器或者事件的调⽤来唤醒
懒加载
懒加载就是将不关键的资源延后加载
懒加载的原理就是只加载⾃定义区域(通常是可视区域,但也可以是即将进⼊可视区域)内需要加载的东⻄。对于图⽚来说,先设置图⽚标签的 src 属性为⼀张占位图,将真实的图⽚资源放⼊⼀个⾃定义属性中,当进⼊⾃定义区域时,就将⾃定义属性替换为 src 属性,这样图⽚就会去下载资源,实现了图⽚懒加载
懒加载不仅可以⽤于图⽚,也可以使⽤在别的资源上。⽐如进⼊可视区域才开始播放视频等
加盐
对于密码存储来说,必然是不能明⽂存储在数据库中的,否则⼀旦数据库泄露,会对⽤户造成很⼤的损失。并且不建议只对密码单纯通过加密算法加密,因为存在彩虹表的关系
通常需要对密码加盐,然后进⾏⼏次不同加密算法的加密
但是加盐并不能阻⽌别⼈盗取账号,只能确保即使数据库泄露,也不会暴露⽤户的真实密码。⼀旦攻击者得到了⽤户的账号,可以通过暴⼒破解的⽅式破解密码。对于这种情况,通常使⽤验证码增加延时或者限制尝试次数的⽅式。
加盐也就是给原密码添加字符串,增加原密码⻓度sha256(sha1(md5(salt + password + salt)))
且⼀旦⽤户输⼊了错误的密码,也不能直接提示⽤户输错密码,⽽应该提示账号或密码错误
前端加密
虽然前端加密对于安全防护来说意义不⼤,但是在遇到中间⼈攻击的情况下,可以避免明⽂密码被第三⽅获取
普通函数
this 总是指向函数的直接调用者
如果有 new 关键字,this 指向 new 出来的实例对象
在事件中,this 指向触发这个事件的对象
IE 下 attachEvent 中的 this 总是指向全局对象 Window
箭头函数中,函数体内的this对象,就是定义时所在作用域的对象,而不是使用时所在的作用域的对象。
(dispatchEvent)(如何进行事件广播?)
W3C: 使用 dispatchEvent 方法
IE: 用 fireEvent 方法
在执行栈中执行一个宏任务。
执行过程中遇到微任务,将微任务添加到微任务队列中。
当前宏任务执行完毕,立即执行微任务队列中的任务。
当前微任务队列中的任务执行完毕,检查渲染,GUI线程接管渲染。
渲染完毕后,js线程接管,开启下一次事件循环,执行下一次宏任务(事件队列中取)。
微任务:process.nextTick、MutationObserver、Promise.then catch finally
**宏任务:**I/O、setTimeout、setInterval、setImmediate、requestAnimationFrame
// 三个常量用于表示状态const PENDING = 'pending'const RESOLVED = 'resolved'const REJECTED = 'rejected'function MyPromise(fn) { const that = this this.state = PENDING // value 变量用于保存 resolve 或者 reject 中传入的值 this.value = null // 用于保存 then 中的回调,因为当执行完 Promise 时状态可能还是等待中,这时候应该把 then 中的回调保存起来用于状态改变时使用 that.resolvedCallbacks = [] that.rejectedCallbacks = [] function resolve(value) { // 首先两个函数都得判断当前状态是否为等待中 if(that.state === PENDING) { that.state = RESOLVED that.value = value // 遍历回调数组并执行 that.resolvedCallbacks.map(cb=>cb(that.value)) } } function reject(value) { if(that.state === PENDING) { that.state = REJECTED that.value = value that.rejectedCallbacks.map(cb=>cb(that.value)) } } // 完成以上两个函数以后,我们就该实现如何执行 Promise 中传入的函数了 try { fn(resolve,reject) }catch(e){ reject(e) }}// 最后我们来实现较为复杂的 then 函数MyPromise.prototype.then = function(onFulfilled,onRejected){ const that = this // 判断两个参数是否为函数类型,因为这两个参数是可选参数 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v=>v; onRejected = typeof onRejected === 'function' ? onRejected : (e)=> { throw e }; // 当状态不是等待态时,就去执行相对应的函数。如果状态是等待态的话,就往回调函数中 push 函数 if(this.state === PENDING) { this.resolvedCallbacks.push(onFulfilled) this.rejectedCallbacks.push(onRejected) } if(this.state === RESOLVED) { onFulfilled(that.value) } if(this.state === REJECTED) { onRejected(that.value) }}
//使用let promise=new MyPromise((resolve,reject)=>{ //请求成功 let res='dddd'; if(true){ resolve(res) }else { reject() }});promise.then(res=>{ console.log(res) //ddd})
// 思路:右边变量的原型存在于左边变量的原型链上function instanceOf(left, right) { let leftValue = left.__proto__ let rightValue = right.prototype while (true) { if (leftValue === null) { return false } if (leftValue === rightValue) { return true } leftValue = leftValue.__proto__ }}
// 传入的对象的原型
function create(obj) {
function F() {}
F.prototype = obj
return new F()
}
当按百分比设定一个元素的高度时,它是相对于父容器的高度计算的。但是,对于一些表示竖向距离的属性,例如 padding-top , padding-bottom , margin-top , margin-bottom 等,当按百分比设定它们时,依据的是父容器的宽度,而不是高度。
行高是指一行文字的高度,具体说是两行文字间基线的距离。CSS中起高度作用的是height和line-height,没有定义height属性,最终其表现作用一定是line-height。
单行文本垂直居中:把line-height值设置为height一样大小的值可以实现单行文字的垂直居中,其实也可以把height删除。
多行文本垂直居中:需要设置display属性为inline-block。
多数显示器默认频率是60Hz,即1秒刷新60次,所以理论上最小间隔为1/60*1000ms = 16.7ms
display属性规定元素应该生成的框的类型;position属性规定元素的定位类型;float属性是一种布局方式,定义元素在哪个方向浮动。
类似于优先级机制:position:absolute/fixed优先级最高,有他们在时,float不起作用,display值需要调整。float 或者absolute定位的元素,只能是块元素或表格。
当一个元素的visibility属性被设置成collapse值后,对于一般的元素,它的表现跟hidden是一样的。
chrome中,使用collapse值和使用hidden没有区别。
firefox,opera和IE,使用collapse值和使用display:none没有什么区别。
原理:有点类似于轮播,整体的元素一直排列下去,假设有5个需要展示的全屏页面,那么高度是500%,只是展示100%,剩下的可以通过transform进行y轴定位,也可以通过margin-top实现
overflow:hidden;transition:all 1000ms ease;
如果有非浮动元素和浮动元素同时存在,并且非浮动元素在前,则浮动元素不会高于非浮动元素;
行内元素与浮动元素发生重叠,边框、背景、内容都会显示在浮动元素之上;
块级元素与浮动元素发生重叠,边框、背景会显示在浮动元素之下,内容会显示在浮动元素之上
<input type=“date” name=“bday”>
<input type=“datetime-local” name=“bdaytime”>
两者都可以用来绘制日历;(对)
后者可以显示本地时间,且时间可以修改;(对)
在滚动中对滚动函数进行节流处理;
滚动中减少导致重绘的操作;
滚动中减少导致重排的操作;
通过给滚动内的子元素开启硬件加速
h2::before{content: url(…)}
用处:配合background-image属性一起使用,用于设置背景图片在盒子中的位置
参数:xpos ypos |x% y% |x y三种,
如果只写第一个水平方向的参数,第二个垂直方向的参数会默认为:center|50%|容器高度的一半px
Xpos:规定水平方向的对齐方式,值有left,right,center
Ypos:规定垂直方向的对齐方式,值有top,bottom,center
x%:规定图片水平方向的距离。你会不会以为这个x%就是父级容器宽度的x%?那你就想错了哦,这里的x%指的是父级容器的宽度减去图片的宽度后的差值的x%。
举个栗子:background-position:50%,20%;
图片的宽度为 imgwidth:100px;高度为 imgheight:100px;
容器的宽度为 conwidth:200px;高度为 conheight:200px;
那么此时图片的左顶点距离容器的左顶点的水平距离就是(conwidth-imgwidth)50%=50px,而不是conwidth50%=100px;由此也可以算出图片的左顶点距离容器的左顶点的垂直距离为20px
padding是边框和内容的分割,这部分必然是透明的,除非设置背景
margin也可以透明,也可以显示背景,它显示的背景是父元素的背景。而padding是显示当前元素的背景。
vw:基于视口的宽度 vh:基于视口的高度,视口被均分成100个单位
vw:viewpoint width,视窗宽度,1vw等于视窗宽度的1%。
vh:viewpoint height,视窗高度,1vh等于视窗高度的1%。
vmin:vw和vh中较小的那个。
vmax:vw和vh中较大的那个。
pt :印刷业上常使用的单位,磅的意思,一般用于页面打印排版。
a标签不能套a标签
有序列表的小写字母如果大于26项再次从 'aa’开始
每个选择器最多只能出现一个伪元素,伪类的个数没有限制
margin: top horizontal bottom /三值语法 上 横向 下/
举例: margin: 1em auto 2em;
<html lang=“en”>
向搜索引擎表示该页面是html语言,并且语言为英文网站,而“en”即表示english
如果是中文页面,可将其改为<html lang=“zh”> ,zh即表示中文
通常我们需要获取某个信息时,都会通过几个缩写的关键字进行检索,那么,在开发中,如何使用HTML5元素进行布局<abbr>标签
The <abbr title=“People’s Republic of China”>PRC</abbr> was founded in 1949.结果:The PRC was founded in 1949.
鼠标在结果的PRC上时会显示People’s Republic of China
在Blink和Webkit的浏览器中,某个元素具有3D或透视变换(perspective transform)的CSS属性,会让浏览器创建单独的图层。
我们平常会使用left和top属性来修改元素的位置,但left和top会触发重布局,取而代之的更好的方法是使用translate,这个不会触发重布局。
解决浏览器渲染的性能问题时,首要目标就是要避免层的重绘和重排。
滥用硬件加速会导致严重性能问题,因为它增加了内存使用,并且它会导致移动端电池寿命减少。
关于web表单登录中用到的图形验证码的实现,发送到客户端的只有图片形式的验证码,服务器端保存cookie对应的图形验证码的正确
在html代码段中,可使“Welcome”在浏览器中从左向右滚动显示的是
<html><body> <marquee scrolldelay="200" direction="right">Welcome!</marquee></body></html>
a元素可以不使用href这个属性,此时为超链接的一个占位符;
在使用table表现数据时,有时候表现出来的会比自己实际设置的宽度要宽,为此需要设置哪些属性
(多)cellpadding=”0” cellspacing=”0”
单元格边距(表格填充)(cellpadding) – 代表表格边框与单元格补白的距离,也是单元格补白之间的距离。
单元格间距(表格间距)(cellspacing) – 代表单元格外面的一个距离,用于隔开单元格与单元格空间;
MVC是一种常见的架构。描述正确的时:React
模型变更之后,只有控制器(Controller)才能驱动视图变更或重新渲染视图。
任何系统都可以使用MVC的设计理念;
模型层里面放的是业务逻辑,视图层有很多表现形式。
React属于MVC框架,是V层,单项数据绑定,可以设置为双向数据绑定
关于跨域的描述正确的是:
CSS文件的加载不受跨域的影响;图片等资源文件加载可以跨域,src本质是get请求,但文字就不一定了,有的是不允许跨域请求的。
‘window.onerror’方法默认情况下无法获取跨域脚本的报错详情;
canvas中使用drawimage贴图会受跨域的影响,解决方案1:如果图片不大不多可以使用base64,解决方案2:实例的image对象的设置img.crossOrigin = ' ';并且在服务器端设置Access-Control-Allow-Origin:*(或运行的域名);
<a id=“yes”>我可以</a> 不可以,a标签没有设置href属性时不能获取到焦点
<a id=“yes” href="#">我可以</a> 这样便可以了。
tabindex:0 或-1 或x
0:tab键可获取焦点;
-1:tab键不可获取焦点;
x:x>0,x越小获取焦点优先级越高;
对于iframe的说法,正确的是:
iframe是用来在网页中插入第三方页面
Iframe的创建比一般的DOM元素慢了1-2个数量级;
Iframe标签会阻塞页面的加载;
局限:
1、创建比一般的 DOM 元素慢了 1-2 个数量级
iframe 的创建比其它包括 scripts 和 css 的 DOM 元素的创建慢了 1-2 个数量级,使用 iframe 的页面一般不会包含太多 iframe,所以创建 DOM 节点所花费的时间不会占很大的比重。但带来一些其它的问题:onload 事件以及连接池(connection pool)
2、阻塞页面加载
及时触发 window 的 onload 事件是非常重要的。onload 事件触发使浏览器的 “忙” 指示器停止,告诉用户当前网页已经加载完毕。当 onload 事件加载延迟后,它给用户的感觉就是这个网页非常慢。window 的 onload 事件需要在所有 iframe 加载完毕后(包含里面的元素)才会触发。在 Safari 和 Chrome 里,通过 JavaScript 动态设置 iframe 的 SRC 可以避免这种阻塞情况
3、唯一的连接池
浏览器只能开少量的连接到 web 服务器。比较老的浏览器,包含 Internet Explorer 6 & 7 和 Firefox 2,只能对一个域名(hostname)同时打开两个连接。这个数量的限制在新版本的浏览器中有所提高。Safari 3+ 和 Opera 9+ 可同时对一个域名打开 4 个连接,Chrome 1+, IE 8 以及 Firefox 3 可以同时打开 6 个绝大部分浏览器,主页面和其中的 iframe 是共享这些连接的。这意味着 iframe 在加载资源时可能用光了所有的可用连接,从而阻塞了主页面资源的加载。如果 iframe 中的内容比主页面的内容更重要,这当然是很好的。但通常情况下,iframe 里的内容是没有主页面的内容重要的。这时 iframe 中用光了可用的连接就是不值得的了。一种解决办法是,在主页面上重要的元素加载完毕后,再动态设置 iframe 的 SRC。
4、不利于 SEO
搜索引擎的检索程序无法解读 iframe。另外,iframe 本身不是动态语言,样式和脚本都需要额外导入。
onchange 是失去焦点且内容改变才会执行函数,如果内容不变则不执行;
onblur 不论内容是否改变,只要失去焦点,就会执行函数;
DHTML具备的三个主要优点是:
(多)动态样式、动态内容、动态定位
DHTML是Dynamic HTML的简称,就是动态的HTML(标准通用标记语言下的一个应用),是相对传统的静态的html而言的一种制作网页的概念。
DHTML 将 HTML、JavaScript、DOM 以及 CSS 组合在一起,用于创造动态性更强的网页。通过 JavaScript 和 HTML DOM,能够动态地改变 HTML 元素的样式。
DHTML实现了网页从Web服务器下载后无需再经过服务的处理,而在浏览器中直接动态地更新网页的内容、排版样式和动画的功能。
html+css+javascript(或其他脚本)的优点:html确定页面框架,css和脚本决定页面样式、动态内容和动态定位。
DHTML 的动态样式的作用是:使网页作者改变内容的外部特征而不强调用户再次下载全部内容
动态内容(Dynamic Content):动态地更新网页内容,可“动态”地插入、修改或删除网页的元件,如文字、图像、标记等。
关于页面加载过程,描述正确的是:
由于html的层次结构已经是树状结构,因此可以实现边加载边生成DOM树;
页面所有资源加载完毕后,会触发onload事件;
css加载不会阻塞DOM树的解析 ;
css加载会阻塞DOM树的渲染 ;
css加载会阻塞后面js语句的执行
关于XML、JSON、HTML5的描述:
JSON比XML在数据编码上更具有效率,更节约时间,数据的体积小,传递的速度更快些;
JSON与JavaScript的交互更加方便,更容易解析处理,更好的数据交互;(对)
XML对数据的类型描述表达比JSON更丰富;(对)
存在一些数据库,直接支持XML或JSON数据的操作,如mongodb,postgresql;(对)
HTML5是一种特殊的XML;(错)
HTML5在跨系统交互面是一种理性的交换格式;(错)
XML比JSON更能表达结构化数据;(错)
对象无初始值或者其值为 0、-0、null、""、false、undefined 或者 NaN,那么对象的值为 false;除了上面几个,它值都为 true(即使值为字符串 “false” )
console.log(({}false)?true:false); // => console.log((NaN0)?true:false);
布尔类型与其它任何类型进行比较,布尔类型将会转换为number类型。
Number转换类型的参数如果为对象返回的就是NaN,
那么Number({})返回的就是NaN
下面几个都会转化为0:
Number()
Number(’’)
Number([])
Number(0)
Number(‘0’)
Number([0])
Number(false)
Number(null)
放在HTML里的哪一部分JavaScript会在页面加载的时候被执行?
(单)<body>标签部分
在HTML body部分中的JavaScripts会在页面加载的时候被执行。放在body部分的脚本通常被用来生成页面的内容。
在HTML head部分中的JavaScripts会在被调用的时候才执行。把脚本放在head部分中时,可以保证脚本在任何调用之前被加载。
之所以把js放在body之后,是为了预防外部js文件过多时,浏览器呈现页面出现延迟,延迟期间浏览器的窗口一片空白。
拖放是HTML5标准的组成部分,若想要把drag1图片放入div1块中,拖放方法如下:
function allowDrop(ev){ ev.preventDefault();}function drag(ev){ ev.dataTransfer.setData("Text",ev.target.id);}function drop(ev){ ev.preventDefault(); var data=ev.dataTransfer.getData("Text"); ev.target.appendChild(document.getElementById(data));} 则,如下HTML代码正确的是()<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div> <img id="drag1" src="img_logo.png" draggable="true" ondragstart="drag(event)" width="336" height="69">
创建带有id属性的DOM元素有什么副作用?
(单)会创建同名的全局变量;
如果一个元素拥有ID属性,那么ID属性的属性值就会成为window对象的属性名.
html5新增了manifest标签,他有什么作用?
(单)应用缓存资源清单
manifest 文件是一个简单的文本文件,列举出了浏览器用于离线访问而缓存的资源。
哪个元素定义了<object>元素的参数?
(单)<param>
param用来为object或applet元素定义的对象或小程序进行初始化参数设置
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。
在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
一个页面title元素只能有一个;
一个页面main元素只能有一个(多个,其他隐藏也可以),因为<main> 标签规定文档的主要内容,<main> 元素不能是以下元素的后代:<article>、<aside>、<footer>、<header> 或 <nav>。
在html5中,哪个元素用于组合标题元素?<hgroup>
hgroup元素是将标题及其子标题进行分组的元素,hgroup元素通常会将h1-h6元素进行分组,比如内容区块的标题及其子元素算一组
关于Canvas和SVG图形的区别
Canvas
Canvas是通过JavaScript的API进行绘图的
依赖分辨率
不支持事件处理器,不能使用绘制对象的相关事件处理,因为我们没有他们的参考(
弱的文本渲染能力
能够以 .png 或 .jpg 格式保存结果图像
最适合图像密集型的游戏,其中的许多对象会被频繁重绘
Canvas 是逐像素进行渲染的。
在 canvas 中,一旦图形被绘制完成,它就不会继续得到浏览器的关注。如果其位置发生变化,那么整个场景也需要重新绘制,包括任何或许已被图形覆盖的对象。
canvas中绘制的元素不可以通过浏览器提供的接口获取到。
SVG
SVG是通过XML进行绘图的
不依赖分辨率
支持事件处理器
最适合带有大型渲染区域的应用程序(比如谷歌地图)
复杂度高会减慢渲染速度
不适合游戏应用
SVG中绘制的元素可以通过浏览器提供的接口获取到。
SVG为了之后的操作,需要记录坐标,所以比较缓慢
不对字符编码,当表单中包含文件上传控件时,需要将enctype设置为:multipart/form-data
enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。
在发送前编码所有字符(默认) application/x-www-form-urlencoded
空格转换为 “+” 加号,但不对特殊字符编码。text/plain
IE6/7/8不支持事件捕获(对)
<blockquote> 标签定义摘自另一个源的块引用。<blockquote> 与 </blockquote>之间的所有文本都会从常规文本中分离出来,经常会在左、右两边进行缩进,而且有时会使用斜体。也就是说,块引用拥有它们自己的空间。
名为“ctx”的变量是某个HTML5画布对象的上下文。以下代码绘制的是什么?Ctx.arc(x,y,r,0,Math.PI,true);
在给定点逆时针绘制一个半圆
当使用地图进行图像搜索时,可以把一幅图片从电脑桌面拖放到地图页面的输入框中,这是使用了HTML5的()API实现的(单)File
文件(File)接口提供有关文件的信息,并允许网页中的 JavaScript 访问其内容。
通常情况下,File对象是来自用户在一个 <input> 元素上选择文件后返回的 FileList 对象,也可以是来自由拖放操作生成的 DataTransfer 对象,或者来自 HTMLCanvasElement 上的mozGetAsFile() API。
部分无视和完全无视的区别?需要注意的是,使用float脱离文档流时,其他盒子会无视这个元素,但其他盒子内的文本依然会为这个元素让出位置,环绕在周围(可以说是部分无视)。而对于使用absolute position脱离文档流的元素,其他盒子与其他盒子内的文本都会无视它。(可以说是完全无视)
关于XML,说法正确与否:
每个合格的xml都有唯一的根元素(对)
XML常用于WebService中用来做数据交换的标准(对)
XML中的数据可以通过XPATH检索查询(对)
document是文档(整个DOM树)的根节点(对)
p元素不能包含任何块级元素(包括自身)
a元素可以包含任何其他元素(除了自身)
li里可以包含一个新的有序或无序列表。
link标签是同时加载的,script标签才会加载完一个再加载另一个,因为JavaScript是一种单线程的脚本语言
id不能为纯数字
Ajax(AsynchronousJavaScriptand XML),直译为“异步的JavaScript与XML技术”,是一种创建交互式网页应用的网页开发技术,与传统的Web应用相比,Ajax通过浏览器与服务器进行少量的数据交换就可以实现网页的异步更新,在不重新加载整个网页的情况下,即可对网页进行更新。
td中设置align= ‘center’,列中内容会居中显示。
ScrollView竖直滚动条,水平方向上的滚动条HorizontalScrollView。
ScrollView中,可以直接包含(一)个组件
dom中HTMLDivElement的正确继承关系是
HTMLDivElement -> HTMLElement -> Element -> Node -> EventTarget
label标签只有两个属性,for(规定 label 绑定到哪个表单元素。)disabled
没有id属性
head 标签中必不少的是<title>
Readonly规定输入的字段为只读,即用户不可修改,但是用户可以通过tab切换到该字段,还可以选中复制该字段。
Web应用特有的状态作用域: 请求作用域,会话作用域,应用上下文。
autoplay 属性规定一旦视频就绪马上开始播放。
preload 属性规定是否在页面加载后载入视频,如果设置了 autoplay 属性,则忽略该属性。
<dfn> 标签可标记那些对特殊术语或短语的定义;
<abbr> 标签指示简称或缩写
HTML 5 支持 HTML 4 中的所有表单控件(对)
html中a标签target属性的默认值是_self
<textarea>没有width属性,但是可以设置cols属性来控制宽度。
<blockquote>长文本引用
假链接中我们通常在a标签的href中添加什么能使得页面不跳转
<a href = "http://www.baidu.com" onclick = "return false" >不能跳转到百度</a><a href = "javascript: ;" >不能跳转</a>
js中的函数就是一个对象,每个函数对象都继承了js的Function类(错)
箭头函数不能调用Function的bind、apply、call方法(Function类具有的方法),没有继承Function类
置换元素:浏览器根据元素的标签和属性,来决定元素的具体显示内容。
<img>、<input>、<textarea>、<select>、<object>
不可替换元素:(x)html 的大多数元素是不可替换元素,即其内容直接表现给用户端(如浏览器)。
例如: <label>label中的内容</label> 标签<label>是一个非置换元素,文字label中的内容”将全被显示。
在js里面添加的属性名使用驼峰法,在css里面使用连接线
a标签有href属性才有下划线标识!
var array=[-1,1,3,4,6,10]; array.sort((a,b)=>Math.abs(a-3)-Math.abs(b-3)); //[3,4,1,6,-1,10]//将每个数进行Math.abs(a - 3)后的大小进行排序
d.setMonth(5); //月份是0-12
d.setDate(40);//如果当月有 30 天,32 为下一个月的第二天, 40 为下一个月的第9天
‘hello’ 和 new String(‘hello’) 的区别,前者是字符串字面值,属于原始类型,而后者是对象。
var str1=new String('str1'); var str2='str2'; console.log(typeof str1);//object console.log(typeof str2);//string console.log(str1 instanceof String);//true console.log(str2 instanceof String);//false
如何获取下面表单 select域的选择部分的文本?obj.options[obj.selectedInded].text
页面有一个按钮button,id为button1,通过原生的js如何禁用?
document.getElementById(“button1”).setAttribute(“disabled”, “true”);或者
document.getElementById(“button1”).disabled = true;
if下的js语句也会进行变量提升
call和apply函数有两个参数,第一个是上下文,第二个是参数组成的数组;如果第一个参数是null,则使用全局对象替代
var a=b=3 时a是局部变量,而b是全局变量
在标准的JavaScript中,Ajax异步执行调用基于哪些机制才能实现?(Event和callback)
Referer是request Header里的内容
不要在块内声明一个函数(严格模式会报语法错误)。如果确实需要在块中定义函数,可以使用函数表达式来声明函数。
javascirpt中的数字在计算机内存储为8Byte
在大数据量的场景下,字符串的连接方式较为高级的是?
+的处理机制是:新建一个临时字符串,将新字符串赋值为a+b,然后返回这个临新字符串并同时销毁原始字符串,所以字符串连接效率较低。所以用Array.join()不会新建临时字符串效率更高。 (当然以上效率问题仅存在于低版本浏览器ie7-及以下,现在的新浏览器基本上都解决了这个问题,效率差不多)
所以在面试时遇到这种题时告诉面试官分两种情况:
旧浏览器(ie7-)下用join()会高效,而新版本浏览器下除了做变量缓存外不需要做别的优化。这样可以侧面表达对刘拉你兼容有所了解。
var A = {n: 4399};
var B = function () {this.n = 9999};
var C = function () {var n = 8888};
B.prototype = A;
C.prototype = A;
var b = new B();
var c = new C();
A.n++;
console.log(b.n);//9999
console.log(c.n);//4400
console.log(b.n);在查找 b.n 是首先查找 b 对象自身有没有 n 属性,如果没有会去原型prototype上查找,当执行 var b = new B() 时,函数内部 this.n=9999(此时this指向b),返回b对象,b对象有自身的n属性,所以返回 9999
console.log(c.n); 同理,当执行 var c = new C() 时,c对象没有自身的n属性,向上查找,找到原型prototype上的 n 属性,因为 A.n++(此时对象A中的n为4400),所以返回4400
var f = function g () { return 23;};//如果是typeof f,结果是function //如果是typeof f(),结果是number //如果是typeof g,结果是undefined. //如果是typeof g(),会立即执行g(),结果是ReferenceError,因为g is not defined
var arr=[{a:1},{}];arr.forEach(function(item,idx){ item.b=idx;});上面代码执行后, arr 的值是:[{a: 1, b: 0}, {b: 1}]arr.forEach(a,b,c) 这个函数用于数组的遍历,其中三个参数abc意义如下 a代表arr[0]---arr[arr.length-1] b代表0---arr.length-1 c代表arr //参数c被省略了 所以第一次循环 a={a:1} , b=0; 执行a.b = 0 后,以为a是一个对象,即给对象啊添加一个b属性,值为0 得到[{a:1,b:0},{}] 第二次循环也是这个意思
静态语言(强类型语言)
静态语言是在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型。
例如:C++、Java、Delphi、C#等。
动态语言(弱类型语言)
动态语言是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。
例如PHP/ASP/Ruby/Python/Perl/ABAP/SQL/JavaScript/Unix Shell等等。
先触发first paint,后触发dom ready
白屏时间(first Paint Time)——用户从打开页面开始到页面开始有东西呈现为止
首屏时间——用户浏览器首屏内所有内容都呈现出来所花费的时间
用户可操作时间(dom Interactive)——用户可以进行正常的点击、输入等操作,默认可以统计domready时间,因为通常会在这时候绑定事件操作
总下载时间——页面所有资源都加载完成并呈现出来所花的时间,即页面 onload 的时间
<div> <input type="button" id = "button1" value="1" onclick="moveBtn(this);"> <input type="button" id = "button2" value="2"/></div><script type="text/javascript">function moveBtn(obj) { var clone = obj.cloneNode(true); // 复制一个button1结点 var parent = obj.parentNode; // 找到button1的父节点 parent.appendChild(clone); // 将复制的结点加入到父节点,也就是button1的复制结点现在在button2后面 parent.removeChild(obj); // 移除原来的button1 }</script>所以最终达到的效果:鼠标单机Button1后把button1结点移到button2结点后面。
若需给子scope发送消息,需使用($broadcast() )方法
$emit() 是向上冒泡
$broadcast() 是向下传播事件
// parseFloat(),解析一个字符串,并返回一个浮点数。// toFixed把数字转换为字符,结果的小数点后有指定位数的数字,按四舍五入取值var num = new Number(15.7857);var a = num.toFixed(); //16 无参数,表示小数点后面位数为0位,然后四舍五入var b = num.toFixed(1);//15.8var c = num.toFixed(3);//15.786var d = num.toFixed(10); //多出的补0//toPrecision()把数字格式化为指定长度var f = num.toPrecision();//15.7857,无参数,返回原数字var g = num.toPrecision(1);//2e+1,参数小于整数部分位数,返回科学计数var h = num.toPrecision(3);//15.8,也是有四舍五入var i = num.toPrecision(10);//15.78570000,长度不够补0
data.now是一个时间戳,Date.now() 方法返回自1970年1月1日 00:00:00 UTC到当前时间的毫秒数。它返回的数据是一个毫秒数,typeof是一个number类型。
Object.prototype.prototype === undefined;//true
Object.prototype只是一个普通对象(普通对象没有prototype属性,所以值是undefined),Object.prototype是js原型链的最顶端,它的__proto__是null
var obj = {};
obj.__proto__ === Object.prototype;//true
obj.prototype === undefined;//true
原型链是基于____proto____形成的,继承是通过prototype实现的。
Function.prototype是个特例,它是函数对象,但是没有prototype属性。其他所有函数都有prototype属性。
Function.prototype.prototype === undefined;//true
内置的Function也是一个函数对象,它是通过自己来创建自己的。
Function.__proto__=== Function.prototype;//true
函数也是对象,因为Function.prototype.____proto____指向Object.prototype。
typeof Function.prototype.__proto__=== “object”;//true
function Foo () { console.log(this.location);}Foo();//返回当前窗口的Location对象//'use strict'条件下,会报TypeError;无'use strict'条件下,this指向window
console.log(1+ +“2”+“2”); //(+“2”)应用了一元加操作符,一元加操作符相当于Number()函数,会将(+“2”)转换为2,1+2+“2”=32
console.log(“A”- “B”+“2”); //在减法中遇到字符串和加法相反,调用Number()函数将字符串转换为数字,不能转换则返回NaN,此时运用加法规则,NaN+“2”,"2"是字符串,则将两者拼接。
console.log(“A”- “B”+2); //这个与上面的不太相同,减法运算后依然为NaN,但是加号后面的为数字2,加法规则中,如果有一个操作数是NaN,则结果为NaN
假设val已经声明,可定义为任何值。则下面js代码有可能输出的结果为:(‘define’)
console.log('Value is ’ + (val != ‘0’) ? ‘define’ : ‘undefine’);
加号优先级高于 三目运算。低于括号。 所以括号中无论真假 加上前边的字符串都为 TRUE 三目运算为TRUE是 输出 define
({} + ‘b’ > {} + ‘a’)返回值是(true)
假如是这样{}+‘b’>{}+'a’中
{}处在语句的起始位置,不会被解析成{}空对象,会被解析为一个表达式,类似于这样
{
}
+‘b’
此时的+‘b’是一个表达式值为NaN
第二个{}并没有处在语句的起始位置,所以会被解析成为空对象
此时的{}+‘a’ 结果为【object object】a
所以{}+‘b’>{}+'a’结果为false
而({}+‘b’>{}+‘a’)结果为true
因为上面的表达式解析后的结果是【object object】b >【object object】a
此时会按照ASCII码进行比较
{} + ‘b’ -> NaN
{} + ‘a’ -> NaN
{} + ‘b’ > {} + ‘a’ -> false
({} + ‘b’ > {} + ‘a’) -> true
var color = "green";var test4399 = { color: "blue"; getColor: function () { var color = "red"; alert(this.color); }}var getColor = test4399.getColor;getColor();//greentest4399.getColor();//blue
当用户打开一个页面时,想一直停留在当前打开的页面,禁止页面前进和后退,以下正确的是ADA. window.history.forward(1);B. window.history.back(1);C. window.history.go(-1);D. window.history.forward(-1);
B. Window History Back
history.back() 方法加载历史列表中前一个 URL。 这等同于在浏览器中点击后退按钮。
C. 跳转到 history 中指定的一个点
你可以用 go() 方法载入到会话历史中的某一特定页面, 通过与当前页面相对位置来标志 (当前页面的相对位置标志为0).
向后移动一个页面 (等同于调用 back()):window.history.go(-1);
向前移动一个页面, 等同于调用了 forward():window.history.go(1);
<SCRIPT language=“JavaScript”>
javascript:window.history.forward(1);
</SCRIPT>
这种方法是用于防止由下一个页面返回的。 简单的说,页面A(A中有这段代码)转向页面B, 这时,B向A转向是被禁止。
有时候我们再做网页时不希望某个网页通过浏览器的前进后退按钮来后退或前进,可以通过简单的办法达到该效果<body οnbefοreunlοad=“history.go(0)”>这样这个网页就会永远停留再这个页面,不能前进后退了。
var x = new Boolean(false);if (x) { alert('hi'); }var y = Boolean(0);if (y) { alert('hello'); }//的显示结果是hi
此题考查的是 JS 的类型转换:
if(x) 这里期望 x 是一个布尔类型的原始值,而 x 是一个对象,任何对象转为布尔值,都为得到 true(切记!在 JS 中,只有 0,-0,NaN,"",null,undefined 这六个值转布尔值时,结果为 false)。
题目的第二部分,一定要注意 y = Boolean(0),而不是 y = new Boolean(0)。这两个有很大区别,用 new 调用构造函数会新建一个布尔对象,此处没有加 new,进行的是显示类型转换,正如上述第一条所说,0 转换布尔,结果为 false,所以此时 y 的值就是 false。
A 2.toString()B 2..toString()C 2 .toString()D (2).toString()
BCD
.和数字在一块 会优先被认为是数字的小数点 而不是调用方法 所以toString() 前面没有点就报错
A '1' === 1B isNaN(1/0)C 1 in [1]D 1 && 2 > 1
D
B选项。 任何数值除以0都会导致错误而终止程序执行。但是在 JavaScript 中,会返回出特殊的值,因此不会影响程序的执行。 比0大的数除以0,则会得到无穷大,所以 js 用 Infinity 来显示出来。 也就是1/0得到的是Infinity。isNaN(1/0)返回的是false。但是isNaN(0/0)返回的就是true
C选项。in操作符,对于数组属性需要指定数字形式的索引值来表示数组的属性名称(固有属性除外如length)。 所以说在这里,1 in [1]并不是表示数字1在不在数组里。而是表示数组中含不含有1这个索引index值。数组长度为1,所以只含有的index值为0,这个表达式返回fasle。
D选项。1 && 2 > 1,先判断右边的表达式,2>1返回true。1 && true返回的结果也是true。
var foo = {n: 1}; (function (foo) { console.log(foo.n); foo.n = 3; var foo = {n: 2}; console.log(foo.n); })(foo); console.log(foo.n); ///运行的结果是 1 2 3 var foo = {n:1}; (function(foo){ //形参foo同实参foo一样指向同一片内存空间,这个空间里的n的值为1 var foo; //已经声明且赋值的变量再重新声明,重新声明是无效的 console.log(foo.n); //输出1 foo.n = 3; //形参与实参foo指向的内存空间里的n的值被改为3 foo = {n:2}; //形参foo指向了新的内存空间,里面n的值为2. console.log(foo.n); //输出新的内存空间的n的值 })(foo); console.log(foo.n); //实参foo的指向还是原来的内存空间,里面的n的值为3.
A 所有变量在使用之前必须做声明
B JS是面向对象的程序设计语言
C JS是解释性语言
D JS前身是Oak语言
C对。语言是相对于编译型语言存在的,源代码不是直接翻译成机器语言,而是先翻译成中间代码,再由解释器对中间代码进行解释运行。比如Python/JavaScript / Perl /Shell等都是解释型语言。
A。如果是局部变量无需声明,也可以使用。
B面向对象语言提供了类、继承等成分,有识认性、多态性、类别性和继承性四个主要特点。而javascript没有这些,所以B错误。
D选项中JAVA的前身才是Oak,而不是JavaScript。所以D错误。
var obj = {};obj.log = console.log;obj.log.call(console,this);//该代码在浏览器中执行,输出的日志结果是什么?(window)//call方法是用来改变this指向的,调用该方法的obj方法log中的this不再指向obj。没用明确指向的this都指向顶层对象window
function checkState(){ alert("liyuming"); }window.setTimeout(checkState(), 10000); //立即被调用window.setTimeout(checkState, 10000); // 10s后被调用 window.setTimeout("checkState()", 10000); //10s后被调用 注意和第一个的区别 有引号
Math.round(-11.5) -11
Math.round(-11.55) -12
如果参数的小数部分大于0.5,则四舍五入到相邻的绝对值更大的整数,相反则舍入到绝对值更小的整数,如果刚好为0.5,则舍入到相邻的正无穷方向的整数
toFixed(n)只是保留n位小数,也是四舍五入
var result = Math.round(num * 10) / 10四舍五入保留一位小数
JS中slice()方法是选取数组的的一部分,并返回一个新数组,不会改变原数组。
noscript 元素用来定义在脚本未被执行时的替代内容(文本)。
Flash提供了ExternalInterface接口与JavaScript通信,ExternalInterface有两个方法,call和addCallback,call的作用是让Flash调用js里的方法,addCallback是用来注册flash函数让js调用。
document.getElementById的返回值的类型为?Object
document.getElementById(‘id’)返回的类型? Function
for循环是按顺序的,for in 循环是不按顺序的
RegExp 对象有 3 个方法:test()、exec() 和 compile()。
test() 方法用来检测一个字符串是否匹配某个正则表达式,如果匹配成功,返回 true ,否则返回 false;
exec() 方法用来检索字符串中与正则表达式匹配的值。exec() 方法返回一个数组,其中存放匹配的结果。如果未找到匹配的值,则返回
compile() 方法可以在脚本执行过程中编译正则表达式,也可以改变已有表达式。
(()=>{}).length; 。获取方法形参个数,形参为0
1&2 1=0001 2=0010 按位与运算,同为1才为1,否则返回0
+[] 。隐式类型转换,因为[]是对象,所以toPrimitive->valueOf->toString为’’,+空字符串就是Number(‘ ’) = 0,结果就是+’’===0
[1, 2, -3].reducer((a, b) => a - b, 0)。reduce对数组中的每个元素执行一个reducer函数(升序执行),reduce接受2个参数,回调函数和初始值。将其结果汇总为单个返回值。a为累计器累计回调的返回值,b为数组的每一项元素,传入初始值0->0-(1)->(-1)-2->(-3)-(-3)->0
Ajax的优势:1.可搜索性 2.开放性 3.费用 4.易用性 5.易于开发。
Flash的优势:1.多媒体处理 2.兼容性 3.矢量图形 4.客户端资源调度
Ajax的劣势:1.它可能破坏浏览器的后退功能 2.使用动态页面更新使得用户难于将某个特定的状态保存到收藏夹中,不过这些都有相关方法解决。
Flash的劣势:1.二进制格式 2.格式私有 3.flash 文件经常会很大,用户第一次使用的时候需要忍耐较长的等待时间 4.性能问题
<SCRIPT LANGUAGE="JavaScript"> var a="undefined"; var b="false"; var c=""; function assert(aVar){ if(aVar) alert(true); else alert(false); } assert(a); assert(b); assert(c);</SCRIPT>//true true false//变量abc都是字符串型的变量,而不是真正的undefined和false,在判断里都会被认为是真值,显示true,只有空串为false
var arr = [];arr[0] = 0;arr[1] = 1;arr.foo = 'c';console.log(arr.length);//2
var arr = [‘1’,‘2’]这本质上是一系列操作:得到一个数组对象;调用了它的数组方法存入了一些数据,arr.length根据存入数据的数目被修改arr.length,对arr对象的length属性进行一个访问arr.foo = ‘c’ 对arr对象创建一个属性,所以.foo跟.length地位是并列的:就是arr的一个属性,同时arr的数组方法跟这些属性是毫不相关的
以下代码的执行后,str 的值是:Hello Worldvar str = "Hellllo world";str = str.replace(/(l)\1/g, '$1');(l)表示第一个分组里有l \1表示所获取的第1个()匹配的引用 /g表示全局匹配 $1表示第一个分组里的值l (l)\l 表示匹配两个连续字符ll,即ll (l)\l/g 表示全局匹配两个连续字符ll即llllstr.replace(/(l)\1/g, '$1') 表示将ll替换成lHellllo =》 Hello
Function.prototype.a = 'a';Object.prototype.b = 'b';function Person(){};var p = new Person();console.log('p.a: '+ p.a); // p.a: undefinedconsole.log('p.b: '+ p.b); // p.b: b //原型链是通过__proto__实现的
<SCRIPT LANGUAGE="JavaScript">var bb = 1;function aa(bb) { bb = 2; alert(bb);};aa(bb);//2alert(bb);//1</SCRIPT>记住一句话就好了:“ECMA中所有函数的参数都是按值传递的”。 值传递:把一个值类型(也叫基本类型)传递给另一个变量时,其实是分配了一块新的存储空间,因此就本题来说,在内部改变这个值时,其实在函数外部对这个值没有影响。
function test () { var n = 4399; function add () { n++; console.log(n); } return {n: n, add: add}}var result = test();var result2 = test();result.add();result.add();console.log(result.n);result2.add();//输出结果为:4400 4401 4399 4400test构成了一个闭包,result跟result2各自有自己的test作用域,所以最后result2.add()结果是4400,第三个,这里{n:n}是对变量n里的值进行缓存,而不是本身n这个指针变量,这样生成n时候n里存的值是多少返回的对象里值就是多少result跟result2之所有有各自的作用域是两次调用了函数后必然产生的结果,两次调用函数,产生两个闭包留在内存里。至于第三个,如果你并没接触过指针的概念的话(指针其实就是对内存地址的上层说法,因为当我们说内存地址的时候就是在说硬件了,为了实现软硬件分离所以又给了内存地址一个指针的概念用于软件层面)
var k = 0;for(var i=0,j=0;i<10,j<6;i++,j++){ k += i + j;}console.log(k)//30//考察知识点: 逗号表达式 逗号表达式只有最后一项是有效的0+0=0 1+1+0=2 2+2+2=6 3+3+6=12 4+4+12=20 5+5+20=30 下一步j=6循环结束尝试改为第二个条件i<6,j<10, 结果为90。第二个条件判断的是布尔值,取逗号后的最后一个运算符来判断一般判断想要两个条件都满足,中间用&连接
function A(x){ this.x = x;}A.prototype.x = 1;function B(x){ this.x = x;}B.prototype = new A();var a = new A(2), b = new B(3);delete b.x;//解析:2 undefinedfunction A(x){ this.x = x;}A.prototype.x = 1;function B(x){this.x = x;}B.prototype = new A();var a = new A(2), //a.x首先要在自己的构造函数中查找,没有采取原型上找,这里有this.x = x.所以a.x = 2; b = new B(3);//B.prototype = new A();形成原型链delete b.x;//但是delete只能删除自己的x不能删除父级的x. //b.x通过原型链找到构造函数A里面的this.x=x但是没有赋值,所以undefined
var myObject = { foo: "bar", func: function() { var self = this; console.log(this.foo); console.log(self.foo); (function() { console.log(this.foo); console.log(self.foo); }()); } }; myObject.func(); 程序的输出是什么?bar bar undefined bar 1.第一个this.foo输出bar,因为当前this指向对象myObject。 2.第二个self.foo输出bar,因为self是this的副本,同指向myObject对象。 3.第三个this.foo输出undefined,因为这个IIFE(立即执行函数表达式)中的this指向window。 4.第四个self.foo输出bar,因为这个匿名函数所处的上下文中没有self,所以通过作用域链向上查找,从包含它的父函数中找到了指向myObject对象的self。
解释性语言和编译性语言的定义:
计算机不能直接理解高级语言,只能直接理解机器语言,所以必须要把高级语言翻译成机器语言,计算机才能执行高级语言编写的程序。
翻译的方式有两种,一个是编译,一个是解释。两种方式只是翻译的时间不同。
解释性语言的定义:js
解释性语言的程序不需要编译,在运行程序的时候才翻译,每个语句都是执行的时候才翻译。这样解释性语言每执行一次就需要逐行翻译一次,效率比较低。
现代解释性语言通常把源程序编译成中间代码,然后用解释器把中间代码一条条翻译成目标机器代码,一条条执行。
编译性语言的定义:
编译性语言写的程序在被执行之前,需要一个专门的编译过程,把程序编译成为机器语言的文件,比如exe文件,以后要运行的话就不用重新翻译了,直接使用编译的结果就行了(exe文件),因为翻译只做了一次,运行时不需要翻译,所以编译型语言的程序执行效率高。
(function () { var x = foo(); var foo = function foo () { return "foobar"; }; return x;})();//var x;var foo;x = foo();foo = function foo() {...}当执行到 x = foo() 时,由于foo未被定义为函数,所以会返回TypeError: foo is not a function
A /^abc$/
B /…(?=.)/
C /[ab]{2}[^defgh]/
D /[defgh]*/
ACD
B …三个点没问题可以匹配到abc但是()内的字符串也必须匹配到故fail掉
B."."表示匹配除换行符的任意字符,"x(?=y)"匹配’x’仅仅当’x’后面跟着’y’.这种叫做先行断言。所以这里可以理解为:
1.当没有换行符时,只要字符前面是三的倍数/…/,并且后面跟有字符/(?=.)/,就可匹配,
2.有换行符时,每一行要重新匹配,即字符长度独立,从0开始(下划线处为匹配项)
C []内匹配两次a或b故可以为aa、bb、ab、ba、[^defgh]表示匹配除了defgh之外的数故可以匹配;
D []内匹配d或者e或f或g或h,但是*代表匹配0或多次故也可以不匹配
CDN 缓存更方便
突破浏览器并发限制
节约 cookie 带宽
节约主域名的连接数,优化页面响应速度
防止不必要的安全问题
微格式(Microformats)是一种让机器可读的语义化 XHTML 词汇的集合,是结构化数据的开放标准。是为特殊应用而制定的特殊格式。
优点:将智能数据添加到网页上,让网站内容在搜索引擎结果界面可以显示额外的提示。(应 用范例:豆瓣,有兴趣自行 google)
dns 缓存,cdn 缓存,浏览器缓存,服务器缓存。
最基本的: 设置 display 属性为 none,或者设置 visibility 属性为 hidden
技巧性: 设置宽高为 0,设置透明度为 0,设置 z-index 位置在-1000
针对不同的浏览器写不同的 CSS code 的过程,就是 CSS hack
rgba()和 opacity 都能实现透明效果,但最大的不同是 opacity 作用于元素,以及元素内的所有内容的透明度,而 rgba()只作用于元素的颜色或其背景色。(设置 rgba 透明的元素的子元素不会继承透明效果!)
垂直方向:line-height 水平方向:letter-spacing
严格模式下:页面排版及 JS 解析是以该浏览器支持的最高标准来执行
混杂模式:不严格按照标准执行,主要用来兼容旧的浏览器,向后兼容
Quirks 模式(怪癖模式,诡异模式,怪异模式)
为什么扩展 javascript 内置对象不是好的做法?
因为扩展内置对象会影响整个程序中所使用到的该内置对象的原型属性
用 H5+CSS3 解决下导航栏最后一项掉下来的问题
(书)
readonly 只针对 input(text / password)和 textarea 有效, 而 disabled 对于所有的表单元素都有效,当表单元素在使用了 disabled 后,当我们将表单以 POST 或 GET 的方式提交的话,这个元素的值不会被传递出去,而 readonly 会将该值传递出 去
var arrA = [];var arrB = [];var arrC = [];//求出A数组的值for(var i = 0; i < 10000; i++) { arrA.push(i);}//A排序arrA.sort(function(a, b) { return Math.random() - 0.5})//求出B数组的值for(var i = 0; i < arrA.length - 2; i++) { arrB[arrA[i]] = arrA[i];}//如果B数组里的第i项为undefind,打印出i放在arrCfor(var i = 0; i<arrB.length; i++){ if(arrB[i] == undefined){ arrC.push(i); }}console.log(arrC);
var t = 10;function test(test){ t = t + test;//undefined+10=NaN console.log(t); var t = 3;}test(t);console.log(t);答案:NaN 10下列 JavaScript 代码执行后,依次 alert 的结果是var obj = {proto: {a:1,b:2}};function F(){};F.prototype = obj.proto;var f = new F();obj.proto.c = 3;obj.proto = {a:-1, b:-2};alert(f.a);//1alert(f.c);//3delete F.prototype['a'];alert(f.a);//undefinedalert(obj.proto.a);//-1用 js 实现随机选取 10–100 之间的 10 个数字,存入一个数组,并排序。var iArray = [];funtion getRandom(istart, iend){ var iChoice = istart - iend +1; return Math.floor(Math.random() * iChoice + istart;}for(var i=0; i<10; i++){ iArray.push(getRandom(10,100));}iArray.sort();function bar() { return foo; foo = 10; function foo() {} //var foo = 11;}alert(typeof bar());//"function"//console.log(a);//是一个函数var a = 3;function a(){}console.log(a);3
对于 ajax 请求传递的参数,如果是 get 请求方式,参数如果传递中文,在有些浏览器 会乱码,不同的浏览器对参数编码的处理方式不同,所以对于 get 请求的参数需要使用 encodeURIComponent 函数对参数进行编码处理,后台开发语言都有相应的解码 api。对于 post 请求不需要 进行编码
本地对象为独立于宿主环境的 ECMAScript 提供的对象,包括 Array Object RegExp 等可以 new 实例化的对象
内置对象为 Gloal,Math 等不可以实例化的(他们也是本地对象,内置对象是本地对象 的一个子集)
宿主对象为所有的非本地对象,所有的 BOM 和 DOM 对象都是宿主对象,如浏览器自带的 document,window 等对象
function format (num) { var reg=/\d{1,3}(?=(\d{3})+$)/g; return (num + '').replace(reg, '$&,');}function format(num){ num=num+'';//数字转字符串 var str="";//字符串累加 for(var i=num.length- 1,j=1;i>=0;i--,j++){ if(j%3==0 && i!=0){//每隔三位加逗号,过滤正好在第一个数字的情况 str+=num[i]+",";//加千分位逗号 continue; } str+=num[i];//倒着累加数字 } return str.split('').reverse().join("");//字符串=>数组=>反转=>字符串}
(使用原生 JS) 回答出概念即可,下面是几个要点
给需要拖拽的节点绑定 mousedown, mousemove, mouseup 事件
mousedown 事件触发后,开始拖拽
mousemove 时,需要通过 event.clientX 和 clientY 获取拖拽位置,并实时更新位置
mouseup 时,拖拽结束
需要注意浏览器边界的情况
会出现乱码,加 charset=”GB2312”
浏览器内核又可以分成两部分:渲染引擎和 JS 引擎。它负责取得网页的内容(HTML、XML、 图像等等)、整理讯息(例如加入 CSS 等),以及计算网页的显示方式,然后会输出至显示器或打印机。JS 引擎则是解析 Javascript 语言,执行 javascript 语言来实现网页的动态效果
(function(x){ delete x; alert(x);})(1+5);函数参数无法 delete 删除,delete 只能删除通过 for in 访问的属性。当然,删除失败也不会报错,所以代码运行会弹出“6”。
let arr = [12,69,180,8763];let result = arr.reduce(function(temp,item,index){ //temp是中间结果,item是下一个参数,index是索引 alert(temp + ‘,’ + item + ‘,’ + index)});//12,69,1//这也是index从1开始的原因//undefined,180,2//undefined,8763,3let arr = [12,69,180,8763];let result = arr.reduce(function(temp,item,index){ return temp + item;});alert(result);//9024//12 69 =>81//81 180 =>261//261 8763 =>9024
let json = {”a”:12, “b”:5};let str = ‘abc’ + json; alert(str); //abc[object Object]let str = ‘abc’ + JSON.stringify(json); //abc{“a”:12, “b”:5}
是一个特殊一点的函数,generator函数不能写成箭头函数的形式
function *show(){//三种形式,function *show()或function * show()或function* show(), //但这种*两边都贴上的形式不可以,function*show() alert(’a’); yield;//放弃,暂时不往下执行 alert(’b’);}//show()不会执行//因为generator函数不会直接运行函数里面的代码,而是创建了一个generator对象出来let genObj = show();alert(genObj);//[object Generator]genObj.next();//a弹出//遇到yield放弃执行下面代码genObj.next();//b弹出
function *show(num1,num2){
alert(`${num1}`, `${num2}`);//99,88
alert(’a’);
let a = yield;
alert(’b’);
alert(a);//5,原因看下图解析,将5直接传给了a
}
let genObj = show(99,88);//第一个过程传参和正常函数一样传参
genObj.next(12);//第一个next对于传参来说是废的,是没有办法给yield传参的
genObj.next(5);//next里的参数是传给yield的
function *show(){ alert(’a’); yield 12; alert(’b’); } let gen = show(); let res1 = gen.next(); console.log(res1);//{value:12, done:false}//done:false表示还没完成 let res2 = gen.next(); console.log(res2);//{value:undefined, done:true} // function *show(){ alert(’a’); yield 12; alert(’b’); return 55;//最后的结果用return往外给 } let gen = show(); let res1 = gen.next(); console.log(res1);//{value:12, done:false}//done:false表示还没完成 let res2 = gen.next(); console.log(res2);//{value:55, done:true}
let arr = [12,4,5];for(let entry of arr.entries()){ alert(entry);//循环0,12 1,4 2,5}for(let [key,value] of arr.entries()){ alert(`${key}=${value}`); //循环0=12 1=4 2=5 //也一定程度上解决了values()还不支持的问题}
1.函数声明function f() {…}2.函数表达式var f = function () {…}3.Function构造函数var f = new Function(“参数”,”函数体”)//这种方式创建的作用域永远指向全局,而不是它的父
1创建父类以及添加父类的属性和方法
2创建子类
3立即继承
上面实现了继承,但是应该本能地将子类原型的constructor修正回子类的构造函数
4此时再添加子类的属性,
假如3和4颠倒,继承的时候有等号,相当于完完全全把子类重写成了父类的样子
function Person(){}//创建父类Person.prototype.headCount = 1;//添加父类属性Person.prototype.eat = function(){//添加父类方法 console.log(”eating...”);}function Programmer(){}//创建子类Programmer.prototype = Object.create(Person.prototype);//继承aProgrammer.prototype.constructor = Programmer;//将子类原型的constructor修正回来(本能)aProgrammer.prototype.language = “Javascript”;//添加子类属性Programmer.prototype.work = function(){//添加子类方法 console.log(”i am writing code in” + this.language);}var js = new Programmer();console.log(js.eat());//eating...console.log(js.language);//“Javascript”js.language = “JS”;console.log(js.language);//“JS”console.log(js.work());//i am writing code in JS
1创建父类以及添加父类的属性和方法
2创建子类
3立即继承
上面实现了继承,但是应该本能地将子类原型的constructor修正回子类的构造函数
4此时再添加子类的属性,
假如3和4颠倒,继承的时候有等号,相当于完完全全把子类重写成了父类的样子
//举例
function Person(){}//创建父类Person.prototype.headCount = 1;//添加父类属性Person.prototype.eat = function(){//添加父类方法 console.log(”eating...”);}function Programmer(){}//创建子类Programmer.prototype = Object.create(Person.prototype);//继承aProgrammer.prototype.constructor = Programmer;//将子类原型的constructor修正回来(本能)aProgrammer.prototype.language = “Javascript”;//添加子类属性Programmer.prototype.work = function(){//添加子类方法 console.log(”i am writing code in” + this.language);}var js = new Programmer();console.log(js.eat());//eating...console.log(js.language);//“Javascript”js.language = “JS”;console.log(js.language);//“JS”console.log(js.work());//i am writing code in JS
拥有
function F(){};var f = new F();f.name = “cj”;console.log(f.hasOwnProperty(”name”));//true//是否有F.prototype.age = 22;console.log(f.hasOwnProperty(”age”));//false//f对象和原型对象是两个对象,不存在拥有console.log(Object.hasOwnProperty(f, ”name”));//false//不要这么用,因为是对象级别的hasOwnPorpertyconsole.log(F.prototype.isPrototypeOf(f));//true//是否是...的原型console.log(Object.getPrototypeOf(f));//F{}//找f的原型
编译时的多态,典型的代表是方法重载(大概意思就是调用一个参数时,就是一个参数的//A方法,调用两个参数时就是两个参数的A方法),编译时就确定了
JS中不允许同名的方法,后者会覆盖前者
arguments,实参的个数,在函数里才会有这个对象,是类似数组的对象
fucntion demo(a, b){
console.log(demo.length);//形参的个数
console.log(arguments.length);//实参的个数
}
运行时多态:重写
function Person (){
var age = 100;//私有成员,外界访问不了
function pm(){//私有成员
console.log(”private method”);
}
this.name = name;//公有成员
this.text = function(){//公有成员
console.log(”public method”);
}
}
//上面的代码这样写就没有意义了,应该向下面这样写才有意义
function Person (){
var age = 100;
function pm(){
console.log(this.name);
}
this.name = name;//公有成员
this.text = function(){//公有成员
console.log(”public method”);
pm();
}
}
var p1 = new Person(”cj”);
console.log(p1.text());//public method undefined
//因为pm()前面没前缀,所以调用window中的pm(),为undefined
//将代码pm()变换为pm.call(this)将this的指向为Person
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。