if (oldVnode === vnode),他们的引用一致,可以认为没有变化。if(oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text),文本节点的比较,需要修改,则会调用Node.textContent = vnode.text。if( oldCh && ch && oldCh !== ch ), 两个节点都有子节点,而且它们不一样,这样我们会调用updateChildren函数比较子节点,这是diff的核心,后边会讲到。else if (ch),只有新的节点有子节点,调用createEle(vnode),vnode.el已经引用了老的dom节点,createEle函数会在老dom节点上添加子节点。else if (oldCh),新节点没有子节点,老节点有子节点,直接删除老节点。总结遍历过程,有3种dom操作:- 当
oldStartVnode,newEndVnode值得比较,说明oldStartVnode.el跑到oldEndVnode.el的后边了。
- 当
oldEndVnode,newStartVnode值得比较,说明oldEndVnode.el跑到了newStartVnode.el的前边。(这里笔误,应该是“oldEndVnode.el跑到了oldStartVnode.el的前边”,准确的说应该是oldEndVnode.el需要移动到oldStartVnode.el的前边”) - newCh中的节点oldCh里没有, 将新节点插入到
oldStartVnode.el的前边。
在结束时,分为两种情况:
oldStartIdx > oldEndIdx,可以认为oldCh先遍历完。当然也有可能newCh此时也正好完成了遍历,统一都归为此类。此时newStartIdx和newEndIdx之间的vnode是新增的
newStartIdx > newEndIdx,可以认为newCh先遍历完。此时oldStartIdx和oldEndIdx之间的vnode在新的子节点里已经不存在了,调用removeVnodes将它们从dom里删除。
- 当
- 在
init的时候会利用Object.defineProperty方法(不兼容IE8)监听Vue实例的响应式数据的变化从而实现数据劫持能力(利用了JavaScript对象的访问器属性get和set,在未来的Vue3中会使用ES6的Proxy来优化响应式原理)。在初始化流程中的编译阶段,当render function被渲染的时候,会读取Vue实例中和视图相关的响应式数据,此时会触发getter函数进行依赖收集(将观察者Watcher对象存放到当前闭包的订阅者Dep的subs中),此时的数据劫持功能和观察者模式就实现了一个MVVM模式中的Binder,之后就是正常的渲染和更新流程。 - 当数据发生变化或者视图导致的数据发生了变化时,会触发数据劫持的
setter函数,setter会通知初始化依赖收集中的Dep中的和视图相应的Watcher,告知需要重新渲染视图,Wather就会再次通过update方法来更新视图。
- 创建Vue实例对象
init过程会初始化生命周期,初始化事件中心,初始化渲染、执行beforeCreate周期函数、初始化data、props、computed、watcher、执行created周期函数等。- 初始化后,调用
$mount方法对Vue实例进行挂载(挂载的核心过程包括模板编译、渲染以及更新三个过程)。 - 如果没有在Vue实例上定义
render方法而是定义了template,那么需要经历编译阶段。需要先将template字符串编译成render function,template字符串编译步骤如下 :parse正则解析template字符串形成AST(抽象语法树,是源代码的抽象语法结构的树状表现形式)optimize标记静态节点跳过diff算法(diff算法是逐层进行比对,只有同层级的节点进行比对,因此时间的复杂度只有O(n)。如果对于时间复杂度不是很清晰的,可以查看我写的文章ziyi2/algorithms-javascript/渐进记号)generate将AST转化成render function字符串
- 编译成
render function后,调用$mount的mountComponent方法,先执行beforeMount钩子函数,然后核心是实例化一个渲染Watcher,在它的回调函数(初始化的时候执行,以及组件实例中监测到数据发生变化时执行)中调用updateComponent方法(此方法调用render方法生成虚拟Node,最终调用update方法更新DOM)。 - 调用
render方法将render function渲染成虚拟的Node(真正的 DOM 元素是非常庞大的,因为浏览器的标准就把 DOM 设计的非常复杂。如果频繁的去做 DOM 更新,会产生一定的性能问题,而 Virtual DOM 就是用一个原生的 JavaScript 对象去描述一个 DOM 节点,所以它比创建一个 DOM 的代价要小很多,而且修改属性也很轻松,还可以做到跨平台兼容),render方法的第一个参数是createElement(或者说是h函数),这个在官方文档也有说明。 - 生成虚拟DOM树后,需要将虚拟DOM树转化成真实的DOM节点,此时需要调用
update方法,update方法又会调用pacth方法把虚拟DOM转换成真正的DOM节点。需要注意在图中忽略了新建真实DOM的情况(如果没有旧的虚拟Node,那么可以直接通过createElm创建真实DOM节点),这里重点分析在已有虚拟Node的情况下,会通过sameVnode判断当前需要更新的Node节点是否和旧的Node节点相同(例如我们设置的key属性发生了变化,那么节点显然不同),如果节点不同那么将旧节点采用新节点替换即可,如果相同且存在子节点,需要调用patchVNode方法执行diff算法更新DOM,从而提升DOM操作的性能。
webpack本质上是一种事件流的机制,它的工作流程就是将各个插件串联起来,而实现这一切的核心是Tapable。webpack流程:实例化Compiler并调用run方法开启编译,webpack中负责构件和编译的都是Compilation。
项目中使用的webpack插件:
- 1.compression-webpack-plugin:生产环境可采用gzip压缩js和css。在config中将build.productionGzip设置为true,会自动将插件导入,然后安装compression插件,在build项目时,webpack会自动帮你压缩文件
- 2.html-webpack-plugin:更具模板自动生成html代码,并自动引用js和css文件
- 3.extract-text-webpack-plugin:将js文件中引用的样式单独抽离成css文件
- 4.HotModuleReplacementPlugin:热更新
- 5.commonsChunkPlugin:将一些公用代码分割成一个chunk
vue项目登录 juejin.cn/post/684490…
fgb
Host
user-Agent
Accept
Accept-Language、Accept-Charset
Connection:keep-alive
Referer
Origin
手写算法或前端递归的题目
考察要点:1.方法链式调用;2.类的使用和面向对象编程的思路;3.设计模式的应用;4.代码的解耦;5.代码的书写结构和命名
1.创建一个空对象
2.继承函数的原型
3.属性和方法被加入到this引用的对象中。执行参数函数
4.新创建的对象由this所引用,并且最后隐式地返回this。
function _new(fn, ...arg) {
var obj = Object.creat(fn.prototype)
var ret = fn.apply(obj, arg)
return ret instanceOF Object ? ret : obj
return ret instanceOF Object ? ret : obj
}
有赞面经
1.parent{position:relative}.child{position:absoute;top50%;left:50%;transform:translate(-50%, -50%)}
2.parent{dsplay:table}.child{display:table-cell;vertical-align:middle};
3.parent{display:flex}.child{align-items:center;justify-content:center};
2.parent{dsplay:table}.child{display:table-cell;vertical-align:middle};
3.parent{display:flex}.child{align-items:center;justify-content:center};
4.parent{position:relative}.child{position:absolute;top:50%;left:50%;margin-top:-1/2height;margin:-1/2width;height:height;}; 5.parent{position:relative}.child{position:absolute;top:0;right:0;bottom:0;left:0;margin:auto}
阿里面经
数组的ES6新方法:filter,map,reduce,forEach使用场景
什么地方经常使用解构
箭头函数
Vue面试题
强制刷新组件
1.this.$forceUpdate 2.v-if
高频面试点
css
变量类型
原型与原型链
作用域和闭包
性能优化
webpack
Promise
HTTP1/2
安全相关
浏览器缓存策略
基础的数据结构和算法
框架相关
发散性问题