思路1

125 阅读7分钟
1.Diff算法

节点的比较有5种情况
  1. if (oldVnode === vnode),他们的引用一致,可以认为没有变化。

  2. if(oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text),文本节点的比较,需要修改,则会调用Node.textContent = vnode.text

  3. if( oldCh && ch && oldCh !== ch ), 两个节点都有子节点,而且它们不一样,这样我们会调用updateChildren函数比较子节点,这是diff的核心,后边会讲到。

  4. else if (ch),只有新的节点有子节点,调用createEle(vnode)vnode.el已经引用了老的dom节点,createEle函数会在老dom节点上添加子节点。

  5. else if (oldCh),新节点没有子节点,老节点有子节点,直接删除老节点。

    总结遍历过程,有3种dom操作:

    1. oldStartVnodenewEndVnode值得比较,说明oldStartVnode.el跑到oldEndVnode.el的后边了。
    1. oldEndVnodenewStartVnode值得比较,说明 oldEndVnode.el跑到了newStartVnode.el的前边。(这里笔误,应该是“oldEndVnode.el跑到了oldStartVnode.el的前边”,准确的说应该是oldEndVnode.el需要移动到oldStartVnode.el的前边”)
    2. newCh中的节点oldCh里没有, 将新节点插入到oldStartVnode.el的前边。

    在结束时,分为两种情况:

    1. oldStartIdx > oldEndIdx,可以认为oldCh先遍历完。当然也有可能newCh此时也正好完成了遍历,统一都归为此类。此时newStartIdxnewEndIdx之间的vnode是新增的
    1. newStartIdx > newEndIdx,可以认为newCh先遍历完。此时oldStartIdxoldEndIdx之间的vnode在新的子节点里已经不存在了,调用removeVnodes将它们从dom里删除。
2.双向绑定原理
  • init的时候会利用Object.defineProperty方法(不兼容IE8)监听Vue实例的响应式数据的变化从而实现数据劫持能力(利用了JavaScript对象的访问器属性getset,在未来的Vue3中会使用ES6的Proxy来优化响应式原理)。在初始化流程中的编译阶段,当render function被渲染的时候,会读取Vue实例中和视图相关的响应式数据,此时会触发getter函数进行依赖收集(将观察者Watcher对象存放到当前闭包的订阅者Depsubs中),此时的数据劫持功能和观察者模式就实现了一个MVVM模式中的Binder,之后就是正常的渲染和更新流程。
  • 当数据发生变化或者视图导致的数据发生了变化时,会触发数据劫持的setter函数,setter会通知初始化依赖收集中的Dep中的和视图相应的Watcher,告知需要重新渲染视图,Wather就会再次通过update方法来更新视图。
3.Vue生命周期函数
  • 创建Vue实例对象
  • init过程会初始化生命周期,初始化事件中心,初始化渲染、执行beforeCreate周期函数、初始化 datapropscomputedwatcher、执行created周期函数等。
  • 初始化后,调用$mount方法对Vue实例进行挂载(挂载的核心过程包括模板编译渲染以及更新三个过程)。
  • 如果没有在Vue实例上定义render方法而是定义了template,那么需要经历编译阶段。需要先将template 字符串编译成 render functiontemplate 字符串编译步骤如下 :
    • parse正则解析template字符串形成AST(抽象语法树,是源代码的抽象语法结构的树状表现形式)
    • optimize标记静态节点跳过diff算法(diff算法是逐层进行比对,只有同层级的节点进行比对,因此时间的复杂度只有O(n)。如果对于时间复杂度不是很清晰的,可以查看我写的文章ziyi2/algorithms-javascript/渐进记号
    • generate将AST转化成render function字符串
  • 编译成render function 后,调用$mountmountComponent方法,先执行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操作的性能。
4.对Vuex的理解

5.Computed的原理

6.父子组件通信

7.webpack原理和使用
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
8.Vue中key的作用

9.高阶组件

10.项目介绍和项目中遇到的问题
vue项目登录 juejin.cn/post/684490…
fgb

11.VUE3.0


12.Vue路由怎么检测到路由变化


13. 301 302 307 308 401 403

1.http请求报文
Host
user-Agent
Accept
Accept-Language、Accept-Charset
Connection:keep-alive
Referer
Origin





手写算法或前端递归的题目

实现debounce 限制操作频率
实现throttle
实现bind,call,apply
打印所有html里所有标签
实现一个lazyman
考察要点:1.方法链式调用;2.类的使用和面向对象编程的思路;3.设计模式的应用;4.代码的解耦;5.代码的书写结构和命名
实现一个deepclone
实现快速排序
实现一个乱序数组
实现一个Promise
实现一个LRU
求第K大树
二叉树的深度
两数之和
四数之和
找出一个集合所有的子集
实现一个new
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
}
实现sleep







有赞面经
滚动效果 用原生js
元素水平垂直居中
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};
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}
行内元素水平垂直居中
text-align:center;line-height:200px;vertical-align:middle;
Vue的生命周期函数
Vuex的理解
js的类型判断,区别、原理、场景
闭包,this指向
跨域,jsonp

阿里面经
  • 数组的ES6新方法:filter,map,reduce,forEach使用场景
  • 什么地方经常使用解构
  • 箭头函数

Vue面试题
强制刷新组件
1.this.$forceUpdate 2.v-if

高频面试点
css
盒子模型
BFC
Flex
居中
Grid

变量类型
JS的数据类型分类和判断
值类型和引用类型

原型与原型链
原型和原型链定义
继承

作用域和闭包
执行上下文
this
闭包

性能优化
减少首屏时间
打包优化等

webpack
loader
plugin
Tree Shaking
代码分割
打包优化技巧

Promise
Promise及其方法的实现

HTTP1/2
HTTP有什么缺点
HTTP2有什么好处
HTTPS有什么好处,有什么缺点,为什么
TCP,UDP的区别,最佳场景
为什么说HTTPS是安全的
解释一下加密过程
三次握手的过程,为什么握手三次,为什么挥手四次

安全相关
XSS
CSRF

浏览器缓存策略
缓存头相关
浏览器Cookie相关

基础的数据结构和算法
Tree
BFS
DFS
递归
动态规划

框架相关
diff
虚拟dom
生命周期
Event Loop
如何设计一个好的组件

发散性问题
输入URL到页面展示发生了什么