双向绑定的原理实现
当创建Vue实例时,vue会遍历data选项的属性,利用Object.defineProperty() 为属性添加 getter 和 setter 对数据的读取进行劫持(getter用来收集依赖,setter用来派发更新),并且在内部追踪依赖,在属性被访问和修改时通知变化。
每个组件实例会有相应的 watcher 实例,会在组件渲染的过程中记录依赖的所有数据属性(进行依赖收集,还有computed watcher,user watcher实例),之后依赖项被改动时,setter方法会通知依赖与此 data 的 watcher 实例重新计算(派发更新),从而使它关联的组件重新渲染。
一句话总结:
vue.js采用数据劫持结合发布-订阅模式,通过Object.defineProperty() 来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发响应的相应回调。
data为什么是一个函数
因为组件是可以复用的,js里对象是引用关系,如果组件 data 是一个对象,那么子组件中的data属性值会相互污染,产生副作用。所以一个组件的data选项必须是函数,因此每个实例可以维护一份被返回对象的独立的拷贝。而new Vue的实例是不会被复用的,因此不存在以上问题。
Proxy和defineProperty区别
defineProperty 缺点
- 无法检测对象属性的添加或移除,为此需要使用 Vue.set 和Vue.delete 来保证响应系统的运行复合预期
- 无法监控到数组下标及数组长度的变化,当直接通过数组的下标给数组设置值或者改变数组长度时,不能实时显示
- 性能问题,当data中数据比较多且层级比较深的时候,因为要遍历data中的所有数据并给其设置成响应式的,会导致性能下降
区别对比
- Object.defineProperty只能劫持对象的属性,对新增属性需要手动进行 Observe,而Proxy 是直接代理对象
- Proxy内置了一个拦截器的对象,所有的外部访问都得先经过这一层拦截
Proxy和defineProperty区别
- vue用异步队列的方式控制DOM更新和nextTick回调先后执行
- microtask 因为其高优先级特性,能确保队列中的微任务在一次事件循环前被执行完毕
- 考虑兼容问题,vue 做了 microtask 向 macrotask 的降级方案
vue组件传值(待补充)
- props最常见的父子通信接口,但是props是单向数据流的形式,父级prop的更新会向下流动到子组件中,但是反过来不行
- 此时需要借助vue提供的事件监听机制来完成子组件向父组件数据流动更新的功能。在子组件使用$emit定义监听事件名称,在父组件使用v-on监听该事件,在事件中改变父组件的状态。
computed和watch的区别
- computed:是计算属性,依赖其他属性值,并且保存 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取computed 的值才会重新的计算coumputed的值
- watch:更多的是观察,类似于某些函数的监听回调,每当监听的数据变化时都会执行回调进行后续操作
- 相同:都起到监听/依赖一个数据,并进行处理的作用
- 不同:computed主要用于对同步数据的处理,watch则主要用于观测某个值的变化去完成一段开销较大的业务逻辑。能用computed的时候优先用computed,避免多个数据影响其中某个数据时多次调用watch的尴尬情况。
本文深入探讨了Vue.js中的数据双向绑定原理,包括利用Object.defineProperty()进行数据劫持,以及如何通过setter和getter实现数据变化的监听和更新。同时,解释了为何Vue组件的data必须是函数,以防止数据污染。另外,对比了Proxy和defineProperty的差异,指出Proxy在处理对象和属性变化上的优势。最后,讨论了Vue组件间的通信方式,如props的单向数据流和事件监听机制,以及computed和watch的使用场景和区别。
4038

被折叠的 条评论
为什么被折叠?



