1.关于jsjavascript
(1)宏任务和微任务:css
宏任务分类:总体代码的script setTimeout setInterval requrestAnimationFramehtml
微任务分类:new promise().then(回调) process.nextTick(在node运行环境中优先级高于promise())前端
实例:vue
console.log('开始');
setTimeout(function() { console.log('setTimeout'); }) new Promise(function(resolve) { console.log('promise'); }).then(function() { console.log('then'); }) console.log('console');
运行结果: 开始 promise console then setTimetoutjava
解释: 1 执行一个宏任务(栈中没有,就从事件队列中获取)。node
2执行过程当中若是遇到微任务,就将它添加到微任务队列中。react
3宏任务执行完毕后,就当即执行当前微任务队列中全部的微任务(依次执行)。webpack
4.当前宏任务执行完毕,开始检查渲染,而后GUI 线程接管渲染。css3
5.渲染完毕后,js线程继续接管,开始完成下一共宏任务(从事件队列中获取)。
(2)事件循环机制:
1.同步和异步任务分别进入不一样的执行”场所“,同步的进入主线程,异步的进入Event 列表并注册函数。
2.当指定的事情完成时,Event 列表会将这个函数移入 event 队列
3.当栈中代码执行完毕,执行栈中的任务为空时,就会读取任务队列中的事件,去执行对应的回调。
4.如此循环,造成js的事件循环机制
(3)如何理解闭包 ,闭包的使用场景:
闭包就是函数调用本身做用域外的变量,或者说成调用做用域链上的变量,这种引用就叫闭包。 闭包的做用,改变变量的做用域。
应用场景:好比 一个变量触发某个事件的时候会改变值,而另外一个函数根据这个值作响应变化。
(4)es5继承和es6继承,区别:
1.ES5先建立子类,在实例化父类并添加到子类this中
2.ES6先建立父类,在实例化子集中经过调用super方法访问父级后,在经过修改this实现继承
es5继承:实质是先建立子类元素child的实例对象,而后再把父类元素parent的原型对象中的属性赋值给了子类元素chid的实例对象里面,从而实现继承。
1.原型继承 :利用call和apply继承this上面的属性和方法
2.原型链继承:将父类的实例做为子类的原型
3.组合继承:利用call apply 继承属性
利用原型链继承方法
es6继承:es6中采用extend继承
继承用extends,当继承后须要用super()来接收父类的constructor构造函数,否在报错,当new一个子类的时候先把参数传入子类构造函数再经过super()讲父类的构造函数引入,就能够调用父类。
(5)垃圾回收:
Js具备自动垃圾回收机制。垃圾收集器会按照固定的时间间隔周期性的执行。
标记清除:工做原理:是当变量进入环境时,将这个变量标记为“进入环境”。当变量离开环境时,则将其标记为“离开环境”。标记“离开环境”的就回收内存。
引用计数 :工做原理:跟踪记录每一个值被引用的次数。
(6)什么状况下会发生内存泄漏:
1. 意外的全局变量引发的内存泄漏。
缘由:全局变量,不会被回收。
解决:使用严格模式避免。
2. 闭包引发的内存泄漏
缘由:闭包能够维持函数内局部变量,使其得不到释放。
解决:将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中,删除对dom的引用。
3. 没有清理的DOM元素引用
缘由:虽然别的地方删除了,可是对象中还存在对dom的引用
解决:手动删除。
4. 被遗忘的定时器或者回调
缘由:定时器中有dom的引用,即便dom删除了,可是定时器还在,因此内存中仍是有这个dom。
解决:手动删除定时器和dom。
5. 子元素存在引用引发的内存泄漏
缘由:div中的ul li 获得这个div,会间接引用某个获得的li,那么此时由于div间接引用li,即便li被清空,也仍是在内存中,而且只要li不被删除,他的父元素都不会被删除。
解决:手动删除清空。
(7)深拷贝和浅拷贝:
浅拷贝:浅拷贝就是拷贝了一层,除了对象时拷贝的引用类型,其余都是直接值传递,有本身的内存空间的。
深拷贝:深拷贝时拷贝多层,即便是嵌套了对象,也会拷贝出来。
深拷贝的实现方式:
1.对象只有一层的话可使用上面的:手动复制:把一个对象的属性复制给另外一个对象的属性
var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c };
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 20, c: 30 } <-- 沒被改到
console.log(obj2);
3.用把对象转成字符串,再用把字符串转成新的对象。Object.assign()函数是深拷贝 ,不然是浅拷贝。
2.JSON.stringifyJSON.parse
var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.body.a = 20;
console.log(obj1);
// { body: { a: 10 } } <-- 沒被改到
console.log(obj2);
// { body: { a: 20 } }
console.log(obj1 === obj2);
// false
console.log(obj1.body === obj2.body);
可是这种方法也有很多坏处,譬如它会抛弃对象的constructor。也就是深拷贝以后,无论这个对象原来的构造函数是什么,在深拷贝以后都会变成Object。
也就是说,只有能够转成JSON格式的对象才能够这样用,像function没办法转成JSON。
4.递归
5.数组的化 .splice(0)也是深拷贝。
(8)变量提高,函数的提高:
1.变量声明的提高:经过var定义(声明)的变量,在定义语句以前就能够访问到值:undefined
2.函数声明的提高:经过function(声明)的函数,在以前就能够直接调用值:函数定义(对象)
(9)call,apply,bind 区别:
相同点:
一、都是用来改变函数的this对象的指向的。
二、第一个参数都是this要指向的对象。
三、均可以利用后续参数传参。
1.call的语法:函数名.call(obj,"参数1",”参数2“);
2. apply的语法:函数名.apply(obj,[参数1,参数2,参数3……]);
3.bind 的语法:函数名bind(obj,"参数1",”参数2“)();
(10)js设计模式,应用场景:
1.单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点
应用场景: 一个redux只有一个store 就是单列模式。
2.策略模式:定义一系列的算法,把它们一个个封装起来,而且使它们能够相互替换
应用场景: 表单验证方法
优势
能够有效地避免多重条件语句,将一系列方法封装起来也更直观,利于维护
缺点
每每策略集会比较多,咱们须要事先就了解定义好全部的状况
3.代理模式:为一个对象提供一个代用品或占位符,以便控制对它的访问
代理模式主要有三种:保护代理、虚拟代理、缓存代理
保护代理应用场景:保护代理主要实现了访问主体得限制行为,以过滤字符做为简单得例子
虚拟代理模式应用场景:函数得节流,是虚拟代理。
缓存代理:为一些开销大得运算结果提供暂时得缓存,提高效率。 缓存加法操做。
4.迭代器模式:迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不须要暴露该对象的内部表示
应用场景:map foreach
5.发布-订阅模式:也是观察者模式,定义了对象间一种一对多得依赖关系,当一个对象得状态发生改变时,全部依赖于它得对象都将获得通知。
应用场景:redux就是订阅者模式,事件监听也订阅者模式。组件自动发现props或者state变化自动更新,就是观察者模式。
6.命令模式:用一种松耦合的方式来设计程序,使得请求发送者和请求接收者可以消除彼此之间的耦合关系
命令(command)指的是一个执行某些特定事情的指令
应用场景:使用对象字面量得形式定义一个命令。
7.组合模式: 用小得子对象来构建更大得对象,而这些小得子对象自己也许时由更小得”孙对象“构建成得。
应用场景:扫描文件夹种得文件
8.模板方法模式:模板方法模式由两部分结构组成,第一部分时抽象父类,第二部分是具体得实现子类。
应用场景:继承,子类直接调用父类得模板函数来执行。
9.享元模式:享元(flyweight)模式是一种用于性能优化的模式,它的目标是尽可能减小共享对象的数量
强调将对象的属性划分为内部状态(属性)与外部状态(属性)。内部状态用于对象的共享,一般不变;而外部状态则剥离开来,由具体的场景决定
应用场景:一个班级男女测量身高,性别为内部状态,其余属性为外部状态。
10.职责链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链 传递该请求,直到有一个对象处理它为止
应用场景:以展现不一样类型的变量为例,设置一条职责链,能够免去多重if条件分支
11.中介者模式:全部的相关 对象都经过中介者对象来通讯,而不是互相引用,因此当一个对象发生改变时,只须要通知中介者对象便可
12.装饰者模式:
13.状态模式:
14.适配器模式:
15.外观模式:
http://www.javashuo.com/article/p-ghjzqliu-k.html
(11)事件流的三个阶段:
事件的处理过程主要有三个阶段:捕获阶段,目标阶段,冒泡阶段;
1.捕获阶段:当咱们在 DOM 树的某个节点发生了一些操做(例如单击、鼠标移动上去),就会有一个事件发射过去。这个事件从 Window 发出,不断通过下级节点直到触发的目标节点。在到达目标节点以前的过程,就是捕获阶段(Capture Phase)。事件由页面元素接收,逐级向下,到具体的元素。
2.目标阶段:当事件不断的传递直到目标节点的时候,最终在目标节点上触发这个事件,就是目标阶段。具体的元素自己
3.冒泡阶段:事件冒泡即事件开始时,由最具体的元素接收(也就是事件发生所在的节点),而后逐级传播到较为不具体的节点。跟捕获相反,具体元素自己,逐级向上,到页面元素(咱们平时用的事件绑定就是利用的事件冒泡的原理)。
事件捕获:当使用事件捕获时,父级元素先触发,子元素后触发。
事件冒泡:当使用事件冒泡时,子级元素先触发,父元素后触发。
W3C : 任何事件发生时,先从顶层开始进行事件捕获,直到事件触发到达事件源,再从事件源向上进行事件捕获(事件冒泡)。
事件传播的阻止方法:
在W3C中,使用stopPropagation()方法。
在IE下使用cancelBubble = true方法。
阻止默认行为:
在W3c中,使用preventDefault()方法。
(12)判断是不是数组的几种实现方式:
1.Array.isArray(): 返回true
let arr = []; console.log(arr instanceof Array); //true
4.写一个函数方法
let arr = []; var isType = function (obj) { return Object.prototype.toString.call(obj).slice(8,-1); } console.log(isType(arr) == 'Array'); //true
(13)MVC和MVVC模式的区别:
MVC:M仍是表示Modal层,负责与后台交互数据,V表示View,负责页面上DOM的渲染,C表示绑定在DOM元素上的事件,当Controllor中的事件被调用,会去调用Modal中的数据,而后交给View从新渲染数据
MVVC:react、vue这俩个框架的核心理念都是数据驱动页面渲染,同时他们都是MVVM模式的框架,MVVM模式中的M仍是固定表示Modal,V仍是表死View,这俩个基本都是不会发生变化,一个页面必然须要数据和渲染俩个部分,那么变化的是如何将Modal渲染到View的过程变了,在MVVM模式中,将View和Modal绑定在一块儿,只要Modal发生了变化,View就会自动更新,不须要咱们认为的再去写如何操做DOM更新的过程了
(14)数据类型是放入堆?仍是栈?
js中数据对于存储能够分为两种数据类型:基本类型和引用类型
基本类型:Number,String,Boolean,Null,Undefined
这些类型的值存放在栈区,函数调用时传递的是变量的值(值)。
引用类型:Object,Array,Function
这些类型的对象存放在堆区,对象的地址存放在栈区,函数调用时传递的是对象的地址(址)。
(15)函数的科里化?
科里化:是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,而且返回接受余下的参数并且返回结果的新函数的技术。
或者:const curry = ( fn, arr = []) => { return (...args) => { return ( a => { //a是一个数组 if(a.length === fn.length) { return fn(...a) }else{ return curry(fn, a) } })([...arr, ...args]) //这里把arr和args摊开成一个数组赋值给a } }const curry = ( fn, arr = []) => (...args) => ( a => a.length === fn.length? fn(...a) : curry(fn, a))([...arr, ...args])
let curryPlus = curry((a,b,c,d)=>a+b+c+d) curryPlus(1,2,3)(4) //返回10 curryPlus(1,2)(4)(3) //返回10 curryPlus(1,2)(3,4) //返回10
(16)用原生的方式实现数组去重?
function merge(arr) {
if (!Array.isArray(arr) || arr.length == 0)
return [];
var ret = [] ;
for (var i = 0; i < arr.length; i++) {
// 或者 ret.indexOf(arr[i] == -1)
if (arr.indexOf(arr[i]) == i)
{ret.push(arr[i]);}
}
return ret;
}
(17)防抖和节流?
防抖:触发高频事件后N秒内只会执行一次,若是n秒内高频事件再次被触发,则从新计算时间。
举例:在百度搜索时,每次输入以后都会有联想词弹出,这个控制联想词的方法就是不多是输入框内容一改变就触发的,他必定是当你结束输入一段时间以后才触发的。
function debounce(fn,delay){
//记录上一次的延时器
var timer = null;
return function(){
//清除上一次延时器
clearTimeout(timer);
//从新设置新的延时器
timer = setTimeout(function(){
fn.apply(this);
},delay);
}
}
节流:高频事件触发,但在N秒内只会执行一次,因此节流会稀释函数执行的频率
举例:预约一个函数只有在大于等于执行周期时才执行,周期内调用不执行,就像淘宝中抢购某一件热卖商品时,你不断的点击刷新或者购买,但是总有一段时间点击没有效果,这里就是节流。
代码举例:
function scall(fn,delay){
// 记录上一次函数触发的时间
var lastTime = 0;
return function (){
// var nowTime = Date.now();
if(nowTime - lastTime>delay){
fn();
lastTime = nowTime;
}
}
}
document.onscroll = scall(function(){ console.log('scroll事件被触发了'+Date.now());},200)
(18)js异步编程的方法?
1.事件的回调函数
2.定时器
3.promise
4.async ...await
5.generator 函数
2.关于es6
http://www.javashuo.com/article/p-gxswledk-nk.html
(1)箭头函数
1.经过=>函数能够更简洁快速的定义一个函数
2.若是箭头函数不须要传参或须要多个传参,就须要使用()括起来。
3.若是箭头函数的代码块部分多于一条语句,就要使用大括号将他们括起来,并使用return语句返回。
4.若是箭头函数只有一行语句,且不须要返回值,不用写大括号了
(2)Promise的用法以及实现原理
(3)说出es6新特性
(4)set数据结构
Set
自己是一个构造函数,用来生成 Set 数据结构,可用于数组去重
实例:
.add() 添加成员,返回Set结构自己
.size 返回Set实例的成员总数
.delete() 删除某值,返回Set结构自己
.has() 返回一个布尔值,表示该值是否为Set的成员
.clear() 清除全部成员,没有返回值
.keys() 返回键名的遍历器
.values() 返回键值的遍历器
.entries() 返回键值对的遍历器
.forEach() 使用回调函数遍历每一个成员,没有返回值
(5)map数据结构
在JavaScript中对象(Object)本质是键值对的集合,但只能用字符串看成键。而Map 数据结构的出现就是为了解决这个限制,它相似于对象,也是键值对的集合,可是“键”的范围不限于字符串,各类类型的值(包括对象)均可以看成键
.set(key, value) 设置key对应的value,返回 Map 结构。若是key已经有值,则键值会被更新。
.get(key) 读取key对应的键值,若是找不到key,返回undefined。
.has(key) 方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
.delete() 方法删除某个键,返回true,若是删除失败,返回false。
.clear() 方法清除全部成员,没有返回值。
.keys(): 返回键名的遍历器。
.values():返回键值的遍历器。
.entries():返回全部成员的遍历器。
.forEach():遍历 Map 的全部成员。
(6)let和const命令
es5只有两种声明变量的方法:var命令和function命令。es6除了let和const命令,另外两种声明变量的方法: import命令和class命令。因此 es6一共有6种方法。
let和const相同的地方:1.只在声明所在的块级做用域内有效 。
2.不可重复声明。
3.一样存在暂时性死区,只能在声明的位置后面使用。
(7)变量的解构赋值
1.数组解构赋值:
2.对象解构赋值:
3.字符串解构赋值:
4.默认值,无论是对象仍是数组,解构赋值都容许指定默认值:
用途:1.交换变量的值
例子1:
2.从函数返回多个值
// 数组
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
// 对象
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();
3.函数参数的定义
4.提取json数据
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
6.输入模块的指定方法
3.关于css2和css3
(1)BFC:块级格式化上下文"
布局规则:
1.内部的BOX会在垂直方向,一个接一个的放置。
2.box垂直方向的距离由margin决定,属于同一个BFC的两个相邻box的margin会发生重叠。
3.每一个盒子(块盒与行盒)的margin box的左边,与包含块border box 的左边相接触(对于从左往右的格式化,不然相反)。即便存在浮动也是如此。
4.BFC的区域不会与float box重叠。
5.BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。
6.计算bfc的高度时,浮动元素也参与计算。
建立BFC:一、float 的值不是none
二、position的值不是static 或者relative
三、display的值是inline-block、table-cell、flex、table-caption 或者inline-flex
四、overflow的值不是visible
1.BFC的做用:1.利用BFC避免margin重叠
2.自适应两栏布局 left<div> : float :left, right<div>: overflow:hidden
3.清除浮动:当咱们不给父节点设置高度,子节点设置浮动的时候,会发生高度塌 陷,这个时候咱们就要清楚浮动
总结:BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此
由于BFC内部的元素和外部的元素绝对不会互相影响,所以, 当BFC外部存在浮动时,它不该该影响BFC内部Box的布局,BFC会经过变窄,而不与浮动有重叠。一样的,当BFC内部有浮动时,为了避免影响外部元素的布局,BFC计算高度时会包括浮动的高度。避免margin重叠也是这样的一个道理
(2)清除浮动3种方式:
(3)实现垂直水平居中(新老方式)
一、老方式
#wrap{
width:500px;
height:500px;
background:grey;
position:relative;
}
#wrap .box{
width:200px;
height:200px;
background:pick;
//方式1:
position:absolute;
top:50%;
left:50%;
margin-left:-100px;
margin-top:-100px;
//方式2:
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
margin:auto;
//方式3
transform:translate(-50%,-50%);
}
二、新方式
#wrap{
display:flex;
justify-content:center;
align-items:center;
}
4.关于react
redux中间件原里:改装dispath
(1)hoc:
定义:一种React的进阶使用方法,主要仍是为了便于组件的复用。HOC就是一个方法,获取一个组件,返回一个更高级的组件
何时使用hoc?
组件添加或者修改一些特定的props,一些权限的管理,或者一些其余的优化之类的。而若是这个功能是针对多个组件的,同时每个组件都写一套相同的代码,明显显得不是很明智,因此就能够考虑使用HOC。
例子:react-redux的connect方法就是一个HOC,他获取wrappedComponent,在connect中给wrappedComponent添加须要的props。
hoc能够作什么?
1.代码复用,代码模块化
2.增删改props
3.渲染劫持 :组件要在data没有加载完的时候,显示loading。。。
Hoc有什么用例?
1.react redux的connect方法,经过这个hoc方法,监听redux store ,而后把下级组件须要的state(经过mapStateToPtops获取)和action creator(经过mapDispatchToProps 获取)绑定到wrappedComponent的props上
2.logger和debugger 能够用来监控父级组件传入的props的改变:
3.页面权限管理:能够经过hoc对组件进行包裹,当跳转到当前页面的时候,检查用户是否含有对应的权限,若是有的话,渲染页面,若是没有的话,跳转到其余页面(好比无权限页面,或者登录页面)。
使用Hoc须要注意什么?
1.尽可能不要随意修改下级组件须要的props
修改父级传递给下级的props是有必定风险的,可能会形成下级组件发生错误。
2.ref没法获取你想要的ref
由于这里的component通过hoc的封装,已是hoc里面的那个component了,因此你没法获取你想要的那个ref(wrappedComponent的ref)。
解决方法:
a> 像react redux的connect方法同样,在里面添加一个参数,好比withRef,组件中检查到这个flag了,就给下级组件添加一个ref ,并经过getWrappedinstance方法获取。
b> 父级经过传递一个方法,来获取ref
先看父级组件:
component上面绑定的Static方法会丢失
好比:原来在Component上面绑定了一些static方法,MyComponent.staticMethod = o=>o.可是因为通过Hoc的包裹,父级组件拿到的已经不是原来的组件了,因此固然没法获取staicMethod方法了
https://segmentfault.com/a/1190000008112017?_ea=1553893
(2)hook:
(3)虚拟dom的缺点:
(4)dva和redux相比较优缺点:
dva是一个基于redux和redux-saga的数据流方案,dva还额外内置了react-router和fetch,因此也能够理解为一个轻量级的应用框架。
1.dva封装了redux,减小不少重复代码好比action reducers常量
2.dva操做都是在models层,经过namespace做为key,标识不一样的模块state。state存储数据。
3.reducers跟传统的react-redux写法一致,全部的操做放在reducers对象内。
4.异步操做写在effects对象内:
其实*fetchList 就是function *fetchList ,是个Generator状态机
call,put实际上是saga的写法,dva集成了saga。
5.ui组件调用使用@connect包裹就能够从this.props上调用方法和数据。
6.dva-loading能够自动处理loading状态,不用一遍遍的写showLoading和hideLoading。
优势
(5)从3方面说说diff算法:
1.tree Diff
(1)react经过updateDepth对于Virtual DOM树进行层级控制。
(2)对树分层比较,两棵树只对同一层次节点进行比较,若是该节点不存在时,则该节点及其子节点会被彻底删除,不会再进一步比较。
(3)只需遍历一次,就 能完成整棵树DOM树的比较。
(4) diff只简单考虑同层级的节点位置互换,若是时垮层级的话,只有建立节点和删除节点的操做。
2.Component Diff
react对不一样组件间的比较,有三种策略”
(1)同一个类型的两个组件,就按原策略(层级比较)继续比较Virtual DOM树便可。
(2)同一类型的两个组件,组件A变化为组件B时,可能Virtual Dom没有任何变化,若是知道这点(变换的过程当中,Virtual Dom没有改变),可节省大量计算时间,因此用户能够经过shouldComponentUpdate()来判断是否须要diff计算
(3)不一样类型的组件,将一个(将被改变的)组件判断为dirty component (脏组件),从而替换整个组件的全部节点。
若是组件D和组件G的结构类似,可是react判断时不一样类型的组件,则不会比较其结构,而是删除组件D及其子节点,建立组件G及其子节点。
3.Element Diff
当节点处于同一层级时,diff提供三种节点操做:删除、插入、移动。
https://www.jianshu.com/p/3ba0822018cf
(6)react框架的原理:
react的设计原理就是其引入的虚拟dom机制:
一、react用javascript在浏览器端实现了一套虚拟dom api。
二、基于react开发的时候全部的dom构造都是基于虚拟dom进行的
三、每当有state更改的时候,react就从新render一整套虚拟dom树,
react机制会将当前的整个dom树和上一次的dom树进行对比
取到diff,进行真实的dom更改。
四、其实state也有一部分实现的是数据、html片断绑定,
直接更新的数据是包含的
深层次一点就是react的diff算法是怎么理解的。
错误的看法:我曾经觉得diff算法,就是深层次的diff,算法运算时只比较
不一样的。但其实当时浅显的想法,确实是diff运算的结果,但不是
diff运算的算法。
一、tree diff
React对Virtual DOM树进行层级控制,只会对相同层级的DOM节点进行比
较,即同一个父元素下的全部子节点,当发现节点已经不存在了,则会删除掉
该节点下全部的子节点,不会再进行比较。这样只须要对DOM树进行一次遍
历,就能够完成整个树的比较。
即便说a节点以及他的子节点被移动,可是react只关注同级比较,在第二层
把a及其子节点删了,在第三层再从新建立,因此diff运算量大,影响性能
不建议setState直接更改树的结构。最好是state颗粒度小,只改变树中
的某一个小的节点,那么diff的时候只会深度比较这一个小节点。
二、componnet diff
假如说由于某个条件切换,因此要显示不一样的组件。
一、比较两个组件的类型(D和G)
二、若是(D和G)不是同一类型,进行diff算法,分析会影响性能
直接删掉上一个虚拟dom组件。 从新建立新的组件。
若是是同一类型的组件,会按照层级策略深层对比每一个节点。
三、element diff
精确的对属于同一层级的节点diff时,提供了3种节点操做,分别为INSERT_MARKUP(插入),MOVE_EXISTING(移动),REMOVE_NODE(删除)。
若是同一层级,没有这个新节点会新增插入
若是同一层级,若是有新节点,可是属性不同,会复用节点,赋值属性
若是同一层次,旧dom有,新dom没有,会删除这个节点。
原文连接:https://blog.csdn.net/running_shuai/java/article/details/80284698
总结:setState()触发一次组件重绘,其实就是虚拟dom从新生成,除非在
shouldComponentUpdate()中实现了一些条件渲染逻辑。来容许和阻止是否须要
调用指定组件的 render 方法。其实这个深刻逻辑就是他触发了render,只是是
否触发了内部的diff算法,return false 的时候,不diff,render出来的新
旧dom同样。diff算法的复杂度为0。
(7)redux:
1>redux 是一个独立专门用于作状态管理的js库,不是react插件库
2>做用:集中式管理react应用中多个组件共享的状态和从后台获取的数据。
react-redux简化redux的编码
redux-thunk实现redux的异步编程
使用redux devTools实现chrome 中redux的调试
(8)为何虚拟dom会提升性能?
(9)this.setStatus 是异步仍是同步?
setState
只在合成事件和钩子函数中是“异步”的,在原生事件和 setTimeout
中都是同步的。setState
的“异步”并非说内部由异步代码实现,其实自己执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新以前,致使在合成事件和钩子函数中无法立马拿到更新后的值,形式了所谓的“异步”,固然能够经过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。setState
的批量更新优化也是创建在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中若是对同一个值进行屡次 setState
, setState
的批量更新策略会对其进行覆盖,取最后一次的执行,若是是同时 setState
多个不一样的值,在更新时会对其进行合并批量更新。
(10)生命周期?
5.前端优化
6.前端工程化
1.服务端模块化
1、commonJS 对模块的定义很是简单,主要分为模块引用,模块定义和模块标识3个部分。
1)模块的引用
var add = require('./add.js);
2) 模块定义
module.exports.add = function(){
...
}
3)能够在一个文件中引入模块并导出另外一个模块
var add = require('./add .js');
module.exports.increment = function(){
return add (val,1);
}
其实 ,一个文件表明一个模块,一个模块除了本身的函数做用域以外,最外层还有一个模块做用域,module就是表明这个模块,
exports是module的属性,require也是这个模块的上下文中,用来引入外部模块。
3)模块标识
模块标识就是require()函数的参数,规范是这样的
1.必须是字符串
2.能够是以./ ../开头的相对路径
3.能够是绝对路径
4.能够省略后缀名
2、node.js 模块化实现
1.node中一个文件 就是一个模块-----module
一个模块就是一个Module的实例
2.node模块分类:核心模块和文件模块
核心模块:就是node内置的模块好比http,path等。在node的源码的编译时,核心模块就一块儿被编译进了二进制执行文件,部分核心模块(内建模块)被直接加载进内存中。
文件模块:就是外部引入的模块如node—modules里面经过npm按装模块,或者咱们项目工程里本身写一个js文件或者json文件。
node模块的引入过程,通常要通过三个步骤
路径分析
文件定位
编译执行
核心模块:会省略 文件定位和编译执行,而且在路径分析中会优先判断,加载速度比通常模块更快。标识:require(‘http’);
文件模块:三个步骤都要经历。require('./c.js');以. / 或者.. /绝对路径开头。
3、AMD:异步模块加载规范与CommonJS的主要区别就是异步模块加载,就是模块加载过程当中即便require的模块尚未获取到,也不会影响后面代码的执行。
4、CMD:通用模块规范,与AMD规范的主要区别在于定义模块和依赖引入的部分,AMD须要在声明模块的时候指定全部的依赖,经过形参传递依赖到模块内容中。在依赖示例部分,CMD支持动态引入,require、exports、module经过形参传递给模块,在须要依赖模块时,随时调用require()引入便可。
5、UMD 通用模块规范
6、es6模块
1)导出一个变量
export var name=‘pengpeng’;
2)导出一个函数
export function foo(x,y){}
3)经常使用导出方式(推荐)
const name = ‘dingman’;
const age = ‘18’;
export{name,age};
4)As用法
const s =1;
export {
s as t,
s as m,
}
能够利用as将模块输出屡次。
Es6模块使用-----import
1) 通常用法
import {name,age} from ‘./person,js';
2) As 用法
import {name as personName} from './person.js';
import命令具备提高效果,会提高到整个模块的头部,首先执行,以下也不会报错:
getName();
import {getName} from ’person_module';
3)总体模块加载*
export name = 'xixi';
export age = 23;
// 逐一加载
import {age,name} from './person.js';
// 总体加载
import * as person from './person.js';
console.log(person.name);
console.log(person.age);
es6模块使用 ------export default
使用export default 命令,须要注意的是使用export default命令时,import 是不须要加{}的,而不使用export default时,import是必须加{}。
示例以下:
//person.js export function getName() { ... } //my_module import {getName} from './person.js'; -----------------对比--------------------- //person.js export default function getName(){ ... } //my_module import getName from './person.js';
export default 实际上是导出一个叫作default的变量,因此其后面不能跟变量声明语句。
//错误
export default var a = 1;
值得注意的是 咱们能够同时使用export和export default
commonjs是运行时加载,es6是编译时加载,又有什么区别呢?
//person.js export name = 'dingman'; export default function getName(){ ... } //my_module import getName, { name } from './person.js';
ES6模块的设计思想,是尽可能的静态化,使得编译时就能肯定模块的依赖关系,以及输入和输出的变量。因此说ES6是编译时加载,不一样于CommonJS的运行时加载(实际加载的是一整个对象),ES6模块不是对象,而是经过export命令显式指定输出的代码,输入时也采用静态命令的形式
//ES6模块 import { basename, dirname, parse } from 'path'; //CommonJS模块 let { basename, dirname, parse } = require('path');
七:webpack模块化
https://zhuanlan.zhihu.com/p/41568986
https://zhuanlan.zhihu.com/p/42853909
7.websocket
(1)websocket和http区别?
http协议是用在应用层的协议,他是基于tcp协议的,http协议创建连接也必需要有三次握手才能发送信息。
http连接分为短连接,长连接,短连接是每次请求都要三次握手才能发送本身的信息。即每个request对应一个response。长连接是在必定的期限内保持连接。保持TCP链接不断开。客户端与服务器通讯,必需要有客户端发起而后服务器返回结果。客户端是主动的,服务器是被动的。
WebSocket
WebSocket他是为了解决客户端发起多个http请求到服务器资源浏览器必需要通过长时间的轮训问题而生的,他实现了多路复用,他是全双工通讯。在webSocket协议下客服端和浏览器能够同时发送信息。
创建了WebSocket以后服务器没必要在浏览器发送request请求以后才能发送信息到浏览器。这时的服务器已有主动权想何时发就能够发送信息到服务器。并且信息当中没必要在带有head的部分信息了与http的长连接通讯来讲,这种方式,不只能下降服务器的压力。并且信息当中也减小了部分多余的信息。
(2)webSocket如何实现断线重连?
var ws_heart_i = null;
/**
* websocket 每1分钟发一次心跳
*/
function ws_heart() {
if (ws_heart_i) clearInterval(ws_heart_i);
ws_heart_i = setInterval(function () {
console.log('ws_heart');
var func = function () {
var data = {type: 'ping'};
ws.send(JSON.stringify(data));
};
ws_execute(func);
}, 60000);
}
原文连接:https://blog.csdn.net/sybil06/java/article/details/88821125
8.浏览器存储
9.网络问题
(1)http 请求的所有过程?
1.DNS解析:将域名地址解析为ip地址
-浏览器DNS缓存
-系统DNS缓存
-路由DNS缓存
-网络运营商DNS缓存
-递归搜索:blog.baidu.com
-.com域名下查找DNS解析
-.baidu域名下查找DNS解析
-blog域名下查找DNS解析
-出错了
2.TCP链接,TCP三次握手
-第一次握手,由浏览器发起,告诉服务器我要发送请求了
-第二次握手,由服务器发起,告诉浏览器我准备接受了,你赶忙发送吧
-第三次握手,由浏览器发送,告诉服务器, 我立刻就发了,准备接受吧
3.发送请求
-请求报文,http协议的通讯内容
4.接受响应
-响应报文
5.渲染页面
-碰见HTML标记,浏览器调用HTML解析器解析成Token并构建成dom树
-碰见style/link标记,浏览器调用css解析器,处理css标记并构建cssom树
-碰见script标记,调用JavaScript解析器,处理script代码(绑定事件,修改dom树/cssom树)
-将dom树和cssom树合并成一个渲染树
-根据渲染树来计算布局,计算每一个节点的几何信息(布局)
-将各个节点颜色绘制到屏幕上(渲染)
注意:
这个5个步骤不必定按照顺序执行,若是dom树或cssom树被修改了,可能会执行屡次布局和渲染,
每每实际页面中,这些步骤会执行屡次的
6.断开链接,TCP四次挥手
第一次挥手,由浏览器发起的,发送给服务器,我东西发送完了(请求报文),你准备关闭吧。
第二次挥手,由服务器发起的,告诉浏览器,我东西接收完了(请求报文),我准备关闭了,你也准备吧
第三次挥手,由服务器发起,告诉浏览器,我东西发送完了(响应报文),你准备关闭吧。
第四次挥手,由浏览器发起,告诉服务器,我东西接受完了,我准备关闭了(响应报文),你也准备吧。
(2)如何处理跨域问题?
(3)http缓存机制?
(4)http状态码
状态码
状态代码为3位数字。
1xx:指示信息--表示请求已接收,继续处理。
2xx:成功--表示请求已被成功接收、理解、接受。
3xx:重定向--要完成请求必须进行更进一步的操做。
4xx:客户端错误--请求有语法错误或请求没法实现。
5xx:服务器端错误--服务器未能实现合法的请求。
10 .移动端如何实现适配
11.react选型?
12.react和vue相比较
相同点:
1.都有组件化开发和virtual DOM
2.都支持props进行父子组件间数据通讯
3.都支持数据驱动视图,不直接操做真实DOM,更新状态数据界面就自动更新
4.都支持服务端渲染
5.都有支持native的方案,react的react native ,vue的weex
不一样点:
1.数据绑定:vue实现了数据的双向绑定,react数据流动时单向的。
2.组件写法不同,react推荐的作法是JSX,也就是把html和css所有都写进javascript了,即“all in js” vue推荐的作法是webpack+vue-loader的单文件组件格式,即html,css,js 写在同一个文件。
3.state对象在react应用中不可变的,须要使用setState方法更新状态;在vue中,state对象不是必须的,数据由data属性在vue对象中管理
4.virtual Dom不同,vue会跟踪每个组件的依赖关系,不须要从新渲染整个组件树,而对于react而言,每当应用的状态被改变时,所有组件都会从新渲染,因此react中会须要shouldComponentUpdate 这个生命周期函数方法来进行控制
5.react严格上只针对MVC的view层,vue则是mvvm模式。
12.飞冰和antdesign?