ES6之Proxy的get方法詳解

 更新時間:2019年10月11日 09:38:40   作者:十月七秋   我要評論
這篇文章主要介紹了ES6之Proxy的get方法詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

Proxy是在ES2015(ES6)中新添加內置對象,用于自定義一些基本操作。

這篇文章是我在學習Proxy的時候對于get方法的一些心得。

作為ES2015新定義的內置對象,Proxy 能夠攔截并且自定義對象以及函數的一些基本操作,具有很高的優先級和便利性,能夠讓我們在寫代碼的時候多出一種解決難題的途徑。

Proxy的get方法用于攔截對象屬性的讀取操作,例如 obj.key 和 obj.[key]。在給Proxy的handler參數中設置get方法后,每當進行讀取操作時,會優先調用該get方法,我們可以在這個方法函數中對讀取行為進行攔截。請看下面的代碼:

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。
在這個例子中,我在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還算容易的,但是如果目標對象繼承自其他對象,那么事情就變得有些麻煩了,請看下面的例子:

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屬性,使用的時候仍舊會拋出錯誤。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

最新評論

pc蛋蛋计划下载