Vue3.0的双向绑定将使用Proxy代替Object.defineProperty,据尤大说,速度提高了1倍。javascript
本文咱们来探讨一下Proxy对比Object.defineProperty究竟有哪些优劣呢?java
首先介绍一下什么是Proxy?数组
Proxy在ES6规范中被正式发布,Proxy能够理解成在目标对象以前架设一层“拦截”,外界对该对象的访问,都必须先经过这层拦截,所以提供了一种机制,能够对外界的访问进行过滤和改写。缓存
Proxy语法:app
ES6原生提供Proxy构造函数,用来生成Proxy实例函数
var proxy = new Proxy(target,handler);
Proxy接受两个参数:this
target:要代理目标对象spa
handler: 处理函数,该函数将拦截对应的操做prototype
下面是 Proxy 支持的拦截操做一览,一共 13 种。双向绑定
proxy.foo
和proxy['foo']
。proxy.foo = v
或proxy['foo'] = v
,返回一个布尔值。propKey in proxy
的操做,返回一个布尔值。delete proxy[propKey]
的操做,返回一个布尔值。Object.getOwnPropertyNames(proxy)
、Object.getOwnPropertySymbols(proxy)
、Object.keys(proxy)
、for...in
循环,返回一个数组。该方法返回目标对象全部自身的属性的属性名,而Object.keys()
的返回结果仅包括目标对象自身的可遍历属性。Object.getOwnPropertyDescriptor(proxy, propKey)
,返回属性的描述对象。Object.defineProperty(proxy, propKey, propDesc)
、Object.defineProperties(proxy, propDescs)
,返回一个布尔值。Object.preventExtensions(proxy)
,返回一个布尔值。Object.getPrototypeOf(proxy)
,返回一个对象。Object.isExtensible(proxy)
,返回一个布尔值。Object.setPrototypeOf(proxy, proto)
,返回一个布尔值。若是目标对象是函数,那么还有两种额外操做能够拦截。proxy(...args)
、proxy.call(object, ...args)
、proxy.apply(...)
。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提供兼容。