双向绑定Proxy VS Object.defineProperty

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 种。双向绑定

  • get(target, propKey, receiver):拦截对象属性的读取,好比proxy.fooproxy['foo']
  • set(target, propKey, value, receiver):拦截对象属性的设置,好比proxy.foo = vproxy['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提供兼容。 

相关文章
相关标签/搜索