前言:vue3.0要用Proxy来实现双向绑定,所以先来尝试一下实现方法。vue
1 Object.defineProperty 实现
原来vue2的实现使用Object.defineProperty,监听set,但对于数组直接下标给数组设置值监听不了。数组
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, // 不能再重写defineProperty get: function() { return val; }, set: function(newVal) { console.log('-------通知订阅者--------') val = newVal; } }); }
2 使用Proxy实现prototype
使用Proxy实现原理主要是new一个Proxy对象,代理你的data值,须要注意的一点是,对于数组的方法操做来讲,会产生两次赋值操做,一次是添加值,一次是改变他的length值,而对于Object.defineProperty监听不到的数组下标给数组设置值,Proxy是能够监听到的。双向绑定
function observe(data) { if (!data || typeof data !== 'object') { return; } // 取出全部属性遍历 Object.keys(data).forEach(function(_k) { // Proxy不容许绑定在非对象上 if (data[_k] && typeof data[_k] === 'object') { data[_k] = defineReactive(data[_k]); } }); } function defineReactive(data) { return new Proxy(data, { set(target, key, value, proxy) { // 进行数组操做时,会进行两次set 一次数据改变,一次length改变,两次改变data的值是不变,所以不该该多分发一次消息 if ( Object.prototype.toString.call(data) === "[object Array]" && key === "length" ) { Reflect.set(target, key, value, proxy); return true; } observe(data); Reflect.set(target, key, value, proxy); console.log('-------通知订阅者--------') return true; } });