双向绑定Proxy VS Object.defineProperty

mac2022-06-30  44

Vue3.0的双向绑定将使用Proxy代替Object.defineProperty,据尤大说,速度提升了1倍。

本文我们来探讨一下Proxy对比Object.defineProperty究竟有哪些优劣呢?

 

首先介绍一下什么是Proxy?

Proxy在ES6规范中被正式发布,Proxy可以理解成在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

Proxy语法:

ES6原生提供Proxy构造函数,用来生成Proxy实例

var proxy = new Proxy(target,handler);

Proxy接受两个参数:

target:要代理目标对象

handler: 处理函数,该函数将拦截对应的操作

下面是 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)。

下面介绍两个常用的拦截方法:get方法和set方法。

//get方法用于拦截某个属性的读取操作 //接受三个参数,依次为目标对象、属性名和Proxy实例本身,最后一个参数可选 //set方法用于拦截某个属性的赋值操作 //接受四个参数,一次为目标对象、属性名、属性值和Proxy实例本身,最后一个参数可选 var person = {   name:'Jack',   age:20 }; var handler = {   get(target,key){     if(key in target){       console.log(`${key}被读取`);       return target[key]     }else{       throw new ReferenceError(`Property ${key} does not exist`)     }   },   set(target,key,value){     console.log(`${key}被设置为${value}`)     target[key] = value   } }; let instance = new Proxy(person,handler); instance.name //name被读取 instance.age = 25 //age被设置为25

 

Object.defineProperty缺点:

1. 对数组的支持不好,无法监听到数组的变化,在Vue官方文档说明了可以监听到数组的变动,但只限于push、pop、shift、unshift、splice、sort、reverse方法。实际上是他们对这几种方法进行了重写。

var arrayProto = Array.prototype; var arrayMethods = Object.create(arrayProto); [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ].forEach(function(item){ Object.defineProperty(arrayMethods,item,{ value:function mutator(){ //缓存原生方法,之后调用   console.log('array被访问');   var original = arrayProto[item]   var args = Array.from(arguments)      original.apply(this,args) // console.log(this); }, }) })

2.Object.defineProperty监听的是对象的属性,当一个对象为深层嵌套的时候,必须进行递归遍历,比较麻烦。

  

Proxy对比Object.defineProperty:

优点:

  1. Proxy可以劫持整个对象,这样以来操作便利程度远远优于Object.defineProperty。

  2. Proxy可以直接监听数组的变化,无需进行数组方法重写。

var arr = [1,2,3,4];   var instance = new Proxy(arr,{   get(target,key){   console.log('数组被读取')   return Reflect.get(target,key) }, set(target,key,val){   console.log('监听到数组更新')   return Reflect.set(target,key,val) } }) instance[0] = 5 //监听到数组更新 instance.push(6) //数组被读取 监听到数组更新

  3. Proxy支持13种拦截操作,是Object.defineProperty不具备的。

 

缺点:Proxy的兼容性不是太好,不兼容IE,且无法通过polyfill提供兼容。 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/AIonTheRoad/p/11156123.html

相关资源:详谈Object.defineProperty 及实现数据双向绑定
最新回复(0)