初探 Proxy
前言
Proxy 是 ES6 中原生提供的一個構造函數,字面意思是代理,但更像一種攔截器,在訪問、賦值等基本操作時會先經過事先定義好的攔截方法中,根據訪問信息執行相對應的操作。
用法
Proxy 構造函數接受兩個參數:
new Proxy(target, handler)
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
不僅可用於監聽數據變化,還可以監聽調用數據,構造函數實體化等操作handler
對象具體的參數有 13 個:get(target, propkey, receiver)
set(target, propkey, receiver)
has(target, propkey)
deleteProperty(target, propkey)
ownkeys(target)
getOwnPropertyDescriptor(target, propKey)
defineProperty(target, propkey, propDesc)
preventExtensions(target)
getPrototypeOf(target)
isExtensible(target)
setPrototypeOf(target, proto)
apply(target, object, args) // 調用函數前觸發
construct(target, args) // 構造函數實體化前觸發
比較 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 許多。