vue原理相关

Vue核心概念

  • vue实例化
  • 虚拟dom
  • 模板编译
  • 数据绑定(响应式)
  • 组件化

MVVM

model和view层通过中间的vm连接和驱动。model层数据变化会改变视图,view改变通过事件来修改数据。vue参考了MVVM实现了双向绑定,react是MVC; 但是vue仍然可以通过refs/parent等操作dom,所以不全是mvvm

vue模板解析

  • 1、先将代码转换为AST树
    根据正则匹配,从第一个字符开始,筛选过的就删掉继续index++向后匹配。
    如果匹配开始标签就放入一个stack中,此时如果匹配到结束标签则出栈对比是否一致,不一致报错
  • 2、优化AST树
    找出静态节点并标记,之后就不需要diff了
    递归遍历ast树中的节点,如果没有表达式、v-if、v-for等,就标记static为true
  • 3、生成render函数、在使用new Function(with() {})包裹
    转换成render函数。编译结束。一定要包裹new Function和with来更改上下文环境
    v-if解析出来就是三元表达式,v-for解析出来_l((3),..)
  • 4、render函数执行后得到的是虚拟dom;AST是需要吧代码使用正则匹配生成的,然后转换成render,而虚拟dom则是通过render函数直接生成一个对象

虚拟dom

VDom:三部曲

  • 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;

  • diff 算法 — 比较两棵虚拟 DOM 树的差异;

  • patch 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。

可以查看本文作者写的另一篇详解虚拟 DOM 的文章《深入剖析:Vue核心之虚拟DOM》https://juejin.cn/post/6844903895467032589#heading-14

vue的双向数据绑定、响应式原理

响应式设计重要的三个对象;

  • 监听器 Observer ,用来劫持并监听所有属性(转变成setter/getter形式),如果属性发生变化,就通知订阅者(watcher)
  • 订阅器 Dep,用来收集订阅者(Watcher),对监听器 Observer和订阅者 Watcher进行统一管理,每一个属性数据都有一个dep记录保存订阅他的watcher。
  • 订阅者 Watcher,可以收到属性的变化通知并执行相应的方法,从而更新视图,每个watcher上都会保存对应的dep;(将模板和Observer对象结合生成实例)
  • 解析器 Compile,可以解析每个节点的相关指令,对模板数据和订阅器进行初始化
image.png

如何亮点解答??

1、在生命周期的initState方法中将data,prop,method,computed,watch中的数据劫持, 通过observe方法与Object.defineProperty方法将相关对象转为换Observer对象。

2、然后在initRender方法中解析模板,通过Watcher对象,Dep对象与观察者模式将模板中的 指令与对象的数据建立依赖关系,使用全局对象Dep.target实现依赖收集。

3、当数据变化时,setter被调用,触发Object.defineProperty方法中的dep.notify方法, 遍历该数据依赖列表,执行器update方法通知Watcher进行视图更新(微任务异步更新)。

  1. vue是无法检测到对象属性的添加和删除,但是可以使用全局Vue.set方法(或vm.$set实例方法)。

  2. vue无法检测利用索引设置数组,但是可以使用全局Vue.set方法(或vm.$set实例方法)。

  3. 无法检测直接修改数组长度,但是可以使用splice;

再去结合vue3做的相关优化,阐述;

Object.defineProperty?

  • 必须预先知道要拦截的 key 是什么,所以它并不能检测对象属性的添加和删除。尽管 Vue.js 为了解决这个问题提供 set 和delete 实例方法,但是对于用户来说,还是增加了一定的心智负担。
  • Vue.js 无法判断你在运行时到底会访问到哪个属性,所以对于这样一个嵌套层级较深的对象,如果要劫持它内部深层次的对象变化,就需要递归遍历这个对象,执行 Object.defineProperty 把每一层对象数据都变成响应式的。毫无疑问,如果我们定义的响应式数据过于复杂,这就会有相当大的性能负担
  • 数组实现响应式

Proxy(数据劫持优化)

  • 劫持的是整个对象,那么自然对于对象的属性的增加和删除都能检测到
  • 注意的是 Proxy API 并不能监听到内部深层次的对象变化,因此 Vue.js 3.0 的处理方式是在 getter 中去递归响应式,这样的好处是真正访问到的内部对象才会变成响应式,而不是无脑递归,这样无疑也在很大程度上提升了性能

区别:

1、语法层面上

defineProperty只能响应首次渲染时候的属性,

Proxy需要的是整体监听,不需要关心里面有什么属性,而且Proxy的配置项有13种,可以做更细致的事情,这是之前的defineProperty无法达到的。

2、兼容层面上

vue2.x之所以只能兼容到IE8就是因为defineProperty无法兼容IE8,其他浏览器也会存在轻微兼容问题。

proxy的话除了IE,其他浏览器都兼容,这次vue3还是使用了它,说明vue3直接放弃了IE的兼容考虑。

image.png
image.png

数据发生变化后,dom是怎么更新的?流程?  === watcher.update怎么样更新视图? 将watcher放入一个更新队列里。

待解答、、patch、diff
  https://juejin.cn/post/6947514223169798175#heading-1
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Vue.js实现原理 初始化创建Vue实例对象init过程会初始化生命周期,初始化事件中心,初始化渲染、执行bef...
    阿_洛阅读 1,846评论 0 0
  • 写在前面的话 面多了,问题五花八门,但也有一些规律,比如,今儿的题就是常考题~ (一)Vue的双向绑定原理 实现数...
    赵国星阅读 1,430评论 0 0
  • 互联网寒冬的来袭,如何在面试之前更高效的做好面试准备,是程序员共同关注的问题。 现在面试门槛越来越高,很多开发者对...
    you的日常阅读 4,556评论 0 7
  • 注意右侧的调用队列 进行初始化的时候 this._init() 初始化的时候调用 initState() init...
    晗笑书生阅读 2,540评论 0 1
  • vue面试题 一、vue优点 1.轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十kb; 2.简单...
    没糖_cristalle阅读 5,497评论 0 3