Vue2和Vue3的双向数据绑定原理分析
目录
vue2.x 是如何实现响应式系统的
当你把一个普通的 js 对象传入 vue 实例作为 data 选项,vue 将遍历此对象的所有prototype(属性),并使用 object.defineProperty(),将这些 prototype(属性),全部转换为 getter / setter,在 getter 中收集数据依赖,在 setter 中监听数据变化,一旦数据发生改变,在通知订阅者。
每个组件实例,都对应一个 watcher 实例,它会在组件渲染的过程把 "接触" 过的数据 prototype(属性)记录为依赖,之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染;
defineProperty 的痛点
- 它无法发现对象新增和被删除的属性,当你给一个对象添加一个新的属性,这个新增的属性没有添加到 vue 的数据更新侦查机制里;
Vue.set() 可以让 vue 知道你新增了一个属性,其实 Vue.set 可以让 Vue 知道新增了一个属性。其实 set() 内部也是通过调用 defineProperty() 来实现;
- 当你利用索引直接设置一个数组(new Array(4))或者修改数组的长度时,Vue 不能检测到数组的变动;
- 当对象嵌套的层数特别深(多层嵌套)的时候,递归遍历带来的性能开销就会比较大;
Object.defineProperty 代码的使用
mounted() { // 先定义好一套规则 class Observer { constructor(data) { for (let key of Object.keys(data)) { if (typeof data[key] === "object") { data[key] = new Observer(data[key]); } Object.defineProperty(this, key, { enumerable: true, configurable: true, get() { console.log("You visited" + key); return data[key]; }, set(NewValue) { console.log("You set" + key); console.log("New Value" + NewValue); if (NewValue === data[key]) { return; } data[key] = NewValue; }, }); } } } let obj = { name: "app", age: 18, a: { b: 1, c: { d: 1, }, }, }; let app = new Observer(obj); console.log(app); app.age = 20; app.newProperty = "new attrs"; console.log(app); },
结果:
Proxy 方法的理解
Proxy 在 vue3.0 中上位
可以解决 defineProperty 的痛点,因为本质的原因在于 Proxy 是内置了拦截器对象。所有的外部访问都得先经过这一层拦截,不管是先前定义好的,还是新增的属性,又或者是深层的嵌套属性,访问时都会被拦截;
Reflect.set()方法用于设置对象属性的值,1:目标对象:2:改变参数的名称:3:改变参数的值:4:值是this如果遇到设置器,将提供给目标调用。
此方法返回一个布尔值,该值指示该属性是否已成功设置。
Proxy 代码的使用
mounted() { const obj = { name: "app", age: 19, a: { b: 1, c: 2, }, }; const p = new Proxy(obj, { get(target, propKey, receiver) { console.log("Your visited:" + propKey); // Reflect.set()方法用于设置对象属性的值:1:目标对象:2:改变参数的名称:3:改变参数的值 // 此方法返回一个布尔值,该值指示该属性是否已成功设置。 return Reflect.set(target, propKey, receiver); }, set(target, propKey, value, receiver) { console.log("You set:" + propKey); console.log("New value:" + value); // Reflect.set()方法用于设置对象属性的值,1:目标对象:2:改变参数的名称:3:改变参数的值:4:值是this如果遇到设置器,将提供给目标调用。 // 此方法返回一个布尔值,该值指示该属性是否已成功设置。 return Reflect.set(target, propKey, value, receiver); }, }); p.age = "20"; console.log(p); p.newProperty = "New attribute"; console.log(p); },
结果:
总结
- proxy 是用来操作对象并且扩展对象能到,而 Object.defineProperty() 只是单纯的操作对象的属性;
- Vue2.X 是用 Object.defineProperty() 实现数据响应的,但是受限于 defineProperty() 的实现,必须递归遍历至对象的最底层;
- vue3.0 用 Proxy 来拦截对象,不管对目标执行任何操作,都会先通过 Proxy 的处理逻辑;
- 除了 Vue3.0,还有其他的库也在使用 Proxy。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持科站长。
上一篇:Vue3 + ElementPlus动态合并数据相同的单元格的完整代码
栏 目:JavaScript
下一篇:Vue3的el-table-column增加跳转其他页面的方法
本文标题:Vue2和Vue3的双向数据绑定原理分析
本文地址:https://www.fushidao.cc/wangluobiancheng/3156.html
您可能感兴趣的文章
- 02-11js中基本事件的总结(onclick、onblur、onchange等)
- 02-11详解如何在Node.js中使用中间件处理请求
- 02-11Vue3中Provide和Inject的用法及工作原理详解
- 02-11Vue+vant实现图片上传添加水印
- 02-11快速解决 keep-alive 缓存组件中定时器干扰问题
- 02-11uniapp 使用 tree.js 解决模型加载不出来的问题及解决方法
- 02-11基于uniapp vue3 的滑动抢单组件实例代码
- 02-10JavaScript 中的 Map使用指南
- 02-10vue3中使用print-js组件实现打印操作步骤
- 02-10Vue 中v-model的完整用法及v-model的实现原理解析


阅读排行
推荐教程
- 04-23JavaScript Array实例方法flat的实现
- 04-23THREE.JS使用TransformControls对模型拖拽的代码实例
- 04-23Vue3使用v-if指令进行条件渲染的实例代码
- 04-23vue3+ts项目搭建的实现示例
- 04-23JavaScript实现下载超大文件的方法详解
- 04-23vue如何使用pdf.js实现在线查看pdf文件功能
- 04-23vue.js调用python脚本并给脚本传数据
- 12-18使用JavaScript遍历输出页面中的所有元素的方法详解
- 04-23JS加密解密之保存到桌面书签
- 12-18Vue实现滚动加载更多效果的示例代码