Jun

只要我的心還會跳,腿還能動

我就沒有理由停下前進的步伐

初探 Proxy


前言

Proxy 是 ES6 中原生提供的一個構造函數,字面意思是代理,但更像一種攔截器,在訪問、賦值等基本操作時會先經過事先定義好的攔截方法中,根據訪問信息執行相對應的操作。


用法

Proxy 構造函數接受兩個參數:

new Proxy(target, handler)

範例:

const handler = {
  get(target, propKey, receiver) {
    console.log('this is get')
    return target[propKey] || 'value is not defined'
  },
  set(target, propKey, value, receiver) {
    console.log('this is set')
    return (target[propKey] = value)
  },
}

const p = new Proxy({}, handler)

console.log(p.number)
// this is get
// value is not defined

p.number = 69
// this is set

console.log(p.number)
// this is get
// 69

上面代碼定義了一個擁有 get 和 set 的代理,當訪問 proxy 對象中的 number 時會進入 handler 中的 get 方法並執行,同理,當我們給 proxy 賦值時,會進入 handler 中的 set 方法。

Proxy 中的 get 與 set 方法和 Object.defineProperty 的 descriptor 的 get 與 set 方法很像,但 Proxy 中的 get 與 set 方法更加強大,不僅可以監聽數組的變化,還可以監聽對象原型屬性的變化:

/* Proxy 監聽數組 */

var proxyArray = new Proxy([], {
  get(target, propKey) {
    console.log('監聽數組 get')
    return target[propKey]
  },
  set(target, propKey, value) {
    console.log('監聽數組 set')
    return (target[propKey] = value)
  },
})
console.log(proxyArray[0])
// 監聽數組 get
// undefined

proxyArray[0] = 69
// 監聽數組 set

console.log(proxyArray[0])
// 監聽數組 get
// 69

/* Proxy 監聽對象原型 */

var obj = { number: 100 }

var prototypeObj = Object.create(obj)

var proxyPrototype = new Proxy(prototypeObj, {
  get(target, propKey) {
    console.log('監聽對象原型 get')
    return target[propKey]
  },
  set(target, propKey, value) {
    console.log('監聽對象原型 set')
    return (target[propKey] = value)
  },
})

console.log(proxyPrototype.number)
// 監聽對象原型 get
//  100

proxyPrototype.number = 69
// 監聽對象原型 set

console.log(proxyPrototype.number)
// 監聽對象原型 get
// 69

比較 Proxy 與 defineProperty

defineProperty

let defineObj = {}

console.time('defineProperty')

for (let i = 0; i < 99999; i++) {
  Object.defineProperty(defineObj, `attr${i}`, {
    get() {
      return value
    },
    set(value) {
      return (defineObj[`attr${i}`] = value)
    },
  })
}

console.timeEnd('defineProperty') // defineProperty: 108.210ms

Proxy

let proxy = new Proxy(
  {},
  {
    get(target, propKey) {
      return target[propKey]
    },

    set(target, propKey, value) {
      return (target[propKey] = value)
    },
  }
)

console.time('proxy')

for (let i = 0; i < 99999; i++) {
  proxy[`attr${i}`] = i
}

console.timeEnd('proxy') // proxy: 75.948ms

在 node 環境下運行 Proxy 明顯快上 defineProperty 許多。