响应式入门,你了解vue3.0响应式数据怎么实现吗

你了解vue3.0响应式数据怎么实现吗

响应式入门,你了解vue3.0响应式数据怎么实现吗

文章插图
从 Proxy 说起
什么是Proxy
proxy翻译过来的意思就是”代理“ , ES6对Proxy的定位就是target对象(原对象)的基础上通过handler增加一层”拦截“ , 返回一个新的代理对象 , 之后所有在Proxy中被拦截的属性 , 都可以定制化一些新的流程在上面 , 先看一个最简单的例子const target = {}; // 要被代理的原对象// 用于描述代理过程的handlerconst handler = {get: function (target, key, receiver) {console.log(`getting ${key}!`);return Reflect.get(target, key, receiver);},set: function (target, key, value, receiver) {console.log(`setting ${key}!`);return Reflect.set(target, key, value, receiver);}}// obj就是一个被新的代理对象const obj = new Proxy(target, handler);obj.a = 1 // setting a!console.log(obj.a) // getting a!
上面的例子中我们在target对象上架设了一层handler , 其中拦截了针对target的get和set , 然后我们就可以在get和set中间做一些额外的操作了
注意1:对Proxy对象的赋值操作也会影响到原对象target , 同时对target的操作也会影响Proxy , 不过直接操作原对象的话不会触发拦截的内容~obj.a = 1; // setting a!console.log(target.a) // 1 不会打印 "getting a!"
【响应式入门,你了解vue3.0响应式数据怎么实现吗】注意2:如果handler中没有任何拦截上的处理 , 那么对代理对象的操作会直接通向原对象const target = {};const handler = {};const obj = new Proxy(target, handler);obj.a = 1;console.log(target.a) // 1
既然proxy也是一个对象 , 那么它就可以做为原型对象 , 所以我们把obj的原型指向到proxy上后 , 发现对obj的操作会找到原型上的代理对象 , 如果obj自己有a属性 , 则不会触发proxy上的get , 这个应该很好理解const target = {};const obj = {};const handler = {get: function(target, key){console.log(`get ${key} from ${JSON.stringify(target)}`);return Reflect.get(target, key);}}const proxy = new Proxy(target, handler);Object.setPrototypeOf(obj, proxy);proxy.a = 1;obj.b = 1console.log(obj.a) // get a from {"a": 1}1console.log(obj.b) // 1
ES6的Proxy实现了对哪些属性的拦截?
通过上面的例子了解了Proxy的原理后 , 我们来看下ES6目前实现了哪些属性的拦截 , 以及他们分别可以做什么? 下面是 Proxy 支持的拦截操作一览 , 一共 13 种get(target, propKey, receiver):拦截对象属性的读取 , 比如proxy.foo和proxy['foo'];set(target, propKey, value, receiver):拦截对象属性的设置 , 比如proxy.foo = v或proxy['foo'] = v , 返回一个布尔值;has(target, propKey):拦截propKey in proxy的操作 , 返回一个布尔值 。deleteProperty(target, propKey):拦截delete proxy[propKey]的操作 , 返回一个布尔值;ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for…in循环 , 返回一个数组 。该方法返回目标对象所有自身的属性的属性名 , 而Object.keys()的返回结果仅包括目标对象自身的可遍历属性;getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey) , 返回属性的描述对象;defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs) , 返回一个布尔值;preventExtensions(target):拦截Object.preventExtensions(proxy) , 返回一个布尔值;getPrototypeOf(target):拦截Object.getPrototypeOf(proxy) , 返回一个对象;isExtensible(target):拦截Object.isExtensible(proxy) , 返回一个布尔值;setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto) , 返回一个布尔值 。如果目标对象是函数 , 那么还有两种额外操作可以拦截;apply(target, object, args):拦截 Proxy 实例作为函数调用的操作 , 比如proxy(…args)、proxy.call(object, …args)、proxy.apply(…);construct(target, args):拦截 Proxy 实例作为构造函数调用的操作 , 比如new proxy(…args);