vue的双向绑定的原理是什么()

vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()或者Proxy来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
Vue2.0整体思路
核心:通过Object.defineProperty()来实现对属性的劫持,达到监听数据变动的目的
Vue遍历data对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter,在属性被访问和修改时通知变更。

通过如下代码实现对属性的监听:

var data = https://www.it610.com/article/{name:'Pat'}; observe(data); data.name = 'PatWu'; // 哈哈哈,监听到值变化了 kindeng --> dmq function observe(data) { if (!data || typeof data !== 'object') { return; } // 遍历所有属性 Object.keys(data).forEach(function(key) { defineReactive(data, key, data[key]); }); }; function defineReactive(data, key, val) { observe(val); // 递归处理子属性 Object.defineProperty(data, key, { enumerable: true, configurable: false, get: function() { console.log('监听到了取值: ', val); return val; }, set: function(newVal) { console.log('监听到了值变化: ', val, ' --> ', newVal); val = newVal; } }); }

在渲染过程中会对 vm 上的数据访问,这个时候会触发了据对象的 getter。那么每个对象值的 getter 都持有一个 dep,在触发 getter 的时候会调用 dep.depend() 方法,
从而实现依赖的收集:
// ...省略 function defineReactive(data, key, val) { observe(val); var dep = new Dep(); // 实例化依赖收集对象 Object.defineProperty(data, key, { get: function() { // 依赖收集 dep.depend(); // Dep.target.addDep(this) return val; } // ... 省略 }); }

Dep.target 渲染过程中已经被赋值为渲染 watcher,那么就执行到 addDep 方法, 接着把当前的 watcher 订阅到这个数据持有的 dep 的 subs 中,
这个目的是为后续数据变化时候能通知到哪些 subs 做准备。
// watcher.js function addDep(dep) { // ...省略 dep.addSub(this)}

收集依赖并监听到变化之后就是怎么通知订阅者了,数据变动触发数据对象的setter,setter中会执行dep.notify(),再调用订阅者的update方法实现数据更新渲染。

// ... 省略 function defineReactive(data, key, val) { observe(val); var dep = new Dep(); // 实例化依赖收集对象 Object.defineProperty(data, key, { // ... 省略 set: function(newVal) { if (val === newVal) return; console.log('监听到了值变化: ', val, ' --> ', newVal); val = newVal; dep.notify(); // 通知所有订阅者 } }); } function Dep() { this.subs = []; } Dep.prototype = { addSub: function(sub) { this.subs.push(sub); }, notify: function() { this.subs.forEach(function(sub) { sub.update(); // 触发更新渲染 }); }};

Vue3.0实现方式
Vue 3.0与Vue 2.0的区别仅是数据劫持的方式由Object.defineProperty更改为Proxy代理,其他代码不变。
function observer(data) { const that = this; for(var key in data){ that.deps[key] = []; //初始化所有订阅者对象{msg: [订阅者], info: []} } let handler = { get(target, property) { return target[property]; }, set(target, key, value) { let res = Reflect.set(target, key, value); var watchers = that.deps[key]; watchers.map(item => { item.update(); }); return res; } } // 通过Proxy实现对数据的劫持 this.$data = https://www.it610.com/article/new Proxy(data, handler); }

【vue的双向绑定的原理是什么()】Object.defineProperty 和 Proxy的优缺点:
1.Object.defineProperty的缺点
不能监听数组:因为数组没有getter和setter,因为数组长度不确定,如果太长性能负担太大
只能监听属性,而不是整个对象,需要遍历循环属性
只能监听属性变化,不能监听属性的删减
2.proxy的好处
可以监听数组
监听整个对象不是属性
13种来截方法,强大很多
返回新对象而不是直接修改原对象;
3.proxy的缺点
兼容性不好,而且无法用polyfill磨平;

    推荐阅读