面试时vue响应式原理这么说,全面而有条理

简单来说:

vue实现响应式(双向绑定)主要做了3件事,一是用劫持数据或者代理数据来监听数据变化;二是收集依赖,也就是确定Dom依赖了哪些数据;三是使用了发布订阅模式去实现,当数据变化时自动通知需要更新的视图部分,并进行更新。

具体来说:

vue2利用了js的Object.defineProperty方法去做数据劫持,采用发布/订阅者模式实现了数据变化消息的传递,两者结合起来实现了双向绑定。当我们使用vue构造函数创建一个vue实例时,会传入一个dom、一个data,也就是视图和数据。此时vue构造函数内部做了两件事:

vue构造函数做的第一件事是:

递归遍历data数据对象里的所有属性,为每个属性运用上Object.defineProperty方法,去设置getter和setter,达到劫持的目的。接着就是在get和set里做文章了。在getter中收集依赖,在setter中触发依赖。先收集依赖,就是把用到该数据的地方收集存储起来,然后等属性发生变化时,把之前收集好的依赖循环触发一遍就行了。
1、在属性的getter方法里,进行依赖收集。getter为该属性创建一个发布者对象Dep,以及一个订阅者对象watcher列表(vue用数组来管理),来管理当前这个属性的所有订阅者。所以可以说data中每个属性都拥有一个发布者对象。
2、在属性的setter方法里很简单,每个setter就是一个观察者。如果该属性被重新赋值了,就通知这个属性的所有订阅者,也就是发布消息,由订阅者对象去通知视图更新。

vue构造函数做的第二件事是:

解析模板指令Compile,也是递归的方式遍历所有节点,遍历过程中,会为那些用双花括号{{}}和bind指令、on绑定了data变量的节点,创建一个个订阅者对象watcher,读取这个变量值的时候,就触发了getter就把这个订阅者添加到之前创建的订阅者对象列表中。并且定义视图更新函数(如果是text节点,就改变node.textContent,如果是Element节点就改变node.value),在setter方法触发时就执行视图更新函数,更新DOM。

接着说vue2做数据劫持的缺陷

1、响应化过程需要一次遍历data、props,消耗较大;
2、不支持数组、Set/Map、weakSet/weakMap、Class等类型;
3、新增或删除属性无法监听;
4、数组响应化需要额外实现,数组额外重写7个方法(数组变异);
5、对应的修改语法有限制,增加心智负担;($set、$delete这些)

最后说vue3做数据劫持的方法

vue3采用ES6的Proxy api实现数据劫持。Proxy的代理是针对整个对象的,而不是对象的某个属性,因此不同于Object.defineProperty必须遍历对象每个属性,Proxy只需要做一层代理就可以监听同级结构下的所有属性变化,当然对于深层结构,递归还是需要进行的。Vue3 就用一个Proxy就能解决上面所有的问题,尤雨溪本人说由于不需要遍历,响应化过程能提升100%,内存占用减少50%。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章