ES6之 Proxy 的 get 方法

这篇是我之前写的文章,若有错误,请指正,谢谢!bash


Proxy是在ES2015(ES6)中新添加内置对象,用于自定义一些基本操做。函数

这篇文章是我在学习Proxy的时候对于get方法的一些心得。学习

做为ES2015新定义的内置对象,Proxy 可以拦截而且自定义对象以及函数的一些基本操做,具备很高的优先级和便利性,可以让咱们在写代码的时候多出一种解决难题的途径。ui

Proxy的get方法用于拦截对象属性的读取操做,例如 obj.key 和 obj.[key]。在给Proxy的handler参数中设置get方法后,每当进行读取操做时,会优先调用该get方法,咱们能够在这个方法函数中对读取行为进行拦截。请看下面的代码:spa

const obj = { key: 1 }
const proxy = new Proxy(obj, {
  get: function(target, property, receiver) {
    console.log('get', property)
    return target[property]
  }
})
console.log(proxy.key)
// get key
// 1
复制代码

get方法的参数一共有三个:target是实例化Proxy时使用的对象,在这个例子中是obj;而property是此次读取操做中想要获取的属性名,在这个例子中是key;最后一个参数receiver则是这个实例化的Proxy自身,即proxy。code

在这个例子中,我在get方法的最后返回了target[property],这是为了可以让读取操做可以进行下去。因为Proxy的get方法是最早被调用的,因此这里返回的内容就是咱们读取操做可以得到的结果;若是咱们在这里不返回任何值,那么就会获得undefined。对象

receiver和死循环

要注意的是,千万不要在get方法中读取receiver的属性,由于receiver实质上就是proxy自身,因此receiver.key这句代码就等同于proxy.key,会从新调用get方法致使死循环。继承

const obj = { key: 1 }
const proxy = new Proxy(obj, {
  get: function(target, property, receiver) {
    console.log(receiver.key)
    return target[property]
  }
})
console.log(proxy.key)
// 死循环!
复制代码

原型链上的getter

有时候,咱们会在对象之中使用getter和setter来定制属性的赋值和读取。在这时,若是proxy的get方法内部有使用到target[property]的话,target[property]的值会受到目标对象的getter的影响。所以调用get方法的时候请注意在目标对象中是否有用到getter。原型链

const obj = {
  get key() {
    return 'string'
  },
  set key(value) {
    console.log(`key is ${value}, it is a ${typeof value}`)
  }
}
const proxy = new Proxy(obj, {
  get: function(target, property, receiver) {
    if(typeof target[property] !== 'string') {
      return target[property]
    } else {
      throw new TypeError(`The type of ${property} is String!`)
    }
  }
})
proxy.key = 100
console.log(proxy, obj)
// key is 100, it is a number
// The type of key is String!
复制代码

在上方的例子中,若是访问obj的非数字类型的属性,就会抛出一个错误,可是因为obj中getter的缘由,不管我给key属性赋什么值,在访问key属性的时候确定会抛出错误。 若是仅仅要注意目标对象中的getter还算容易的,可是若是目标对象继承自其余对象,那么事情就变得有些麻烦了,请看下面的例子:get

const parentObj = {
  get key() {
    return 'string'
  },
  set key(value) {
    console.log(`key is ${value}, it is a ${typeof value}`)
  }
}
const obj = Object.create(parentObj)
const proxy = new Proxy(obj, {
  get: function (target, property, receiver) {
    if (typeof target[property] !== 'string') {
      return target[property]
    } else {
      throw new TypeError(`The type of ${property} is String!`)
    }
  }
})
proxy.key = 100 
console.log(proxy.key)
// key is 100, it is a number
// The type of key is String!
复制代码

如代码所示,目标对象obj继承自parentObj,而parentObj中使用了getter方法,那么使用proxy的get方法仍旧会报错。实际运用中原型链可能会很长,getter可能会存在于原型链的任何一个地方中,因此在使用Proxy的get方法时请必定要注意。

可是若是把parentObj上的key遮蔽掉,就不会发生抛出错误的状况了。好比在建立obj的时候申明的key,代码以下:

const parentObj = {
  get key() {
    return 'string'
  },
  set key(value) {
    console.log(`key is ${value}, it is a ${typeof value}`)
  }
}
const obj = Object.create(parentObj, {
  key: {
    value: null,
    writable: true
  }
})
const proxy = new Proxy(obj, {
  get: function (target, property, receiver) {
    if (typeof target[property] !== 'string') {
      return target[property]
    } else {
      throw new TypeError(`The type of ${property} is String!`)
    }
  }
})
proxy.key = 100 
console.log(proxy.key)
// 100
复制代码

一样的,咱们也可使用Object.defineProperty()和Object.assign()这两个方法来达到相同的目的:

Object.defineProperty(obj, 'key', {
  value: null,
  writable: true
})
obj = Object.assign({}, obj, { key: null })
复制代码

可是要注意使用Object.assign()的时候不能这么些:

obj = Object.assign(obj, { key: null })
复制代码

这样写法没法遮蔽掉parentObj上的key属性,使用的时候仍旧会抛出错误。


谢谢阅读,我的成果,请勿转载:)

相关文章
相关标签/搜索