摘要: Proxy的騷操作。 作者:前端小智 原文: "Proxy 的巧用" "Fundebug" 經授權轉載,版權歸原作者所有。 Proxy 介紹 使用 ,你可以將一隻貓偽裝成一隻老虎。下麵大約有6個例子,我希望它們能讓你相信,Proxy 提供了強大的 Javascript 元編程。 儘管它不像其 ...
摘要: Proxy的騷操作。
- 作者:前端小智
- 原文:Proxy 的巧用
Fundebug經授權轉載,版權歸原作者所有。
Proxy 介紹
使用Proxy
,你可以將一隻貓偽裝成一隻老虎。下麵大約有6個例子,我希望它們能讓你相信,Proxy 提供了強大的 Javascript 元編程。
儘管它不像其他ES6功能用的普遍,但Proxy
有許多用途,包括運算符重載,對象模擬,簡潔而靈活的API創建,對象變化事件,甚至Vue 3背後的內部響應系統提供動力。
Proxy
用於修改某些操作的預設行為,也可以理解為在目標對象之前架設一層攔截,外部所有的訪問都必須先通過這層攔截,因此提供了一種機制,可以對外部的訪問進行過濾和修改。這個詞的原理為代理,在這裡可以表示由它來“代理”某些操作,譯為“代理器”。
ES6原生提供了Proxy
構造函數,用來生成Proxy
實例。
var proxy = new Proxy(target, handler);
Proxy
對象的所有用法,都是上面的這種形式。不同的只是handle
參數的寫法。其中new Proxy
用來生成Proxy
實例,target
是表示所要攔截的對象,handle
是用來定製攔截行為的對象。
下麵是 Proxy 最簡單的例子是,這是一個有陷阱的代理,一個get
陷阱,總是返回42
。
let target = {
x: 10,
y: 20
};
let hanler = {
get: (obj, prop) => 42
};
target = new Proxy(target, hanler);
target.x; //42
target.y; //42
target.x; // 42
結果是一個對象將為任何屬性訪問操作都返回“42”。 這包括target.x
,target['x']
,Reflect.get(target, 'x')
等。
但是,Proxy 陷阱當然不限於屬性的讀取。 它只是十幾個不同陷阱中的一個:
- handler.get
- handler.set
- handler.has
- handler.apply
- handler.construct
- handler.ownKeys
- handler.deleteProperty
- handler.defineProperty
- handler.isExtensible
- handler.preventExtensions
- handler.getPrototypeOf
- handler.setPrototypeOf
- handler.getOwnPropertyDescriptor
Proxy 用例
預設值/“零值”
在 Go 語言中,有零值的概念,零值是特定於類型的隱式預設結構值。其思想是提供類型安全的預設基元值,或者用gopher的話說,給結構一個有用的零值。
雖然不同的創建模式支持類似的功能,但Javascript無法用隱式初始值包裝對象。Javascript中未設置屬性的預設值是undefined
。但 Proxy 可以改變這種情況。
const withZeroValue = (target, zeroValue) =>
new Proxy(target, {
get: (obj, prop) => (prop in obj ? obj[prop] : zeroValue)
});
函數withZeroValue
用來包裝目標對象。 如果設置了屬性,則返回屬性值。 否則,它返回一個預設的“零值”。
從技術上講,這種方法也不是隱含的,但如果我們擴展withZeroValue
,以Boolean (false
), Number (0
), String (""
), Object ({}
),Array ([]
)等對應的零值,則可能是隱含的。
let pos = {
x: 4,
y: 19
};
console.log(pos.x, pos.y, pos.z); // 4, 19, undefined
pos = withZeroValue(pos, 0);
console.log(pos.z, pos.y, pos.z); // 4, 19, 0
此功能可能有用的一個地方是坐標系。 繪圖庫可以基於數據的形狀自動支持2D和3D渲染。 不是創建兩個單獨的模型,而是始終將z
預設為 0
而不是undefined
,這可能是有意義的。
負索引數組
在JS中獲取數組中的最後一個元素方式通過寫的很冗長且重覆,也容易出錯。 這就是為什麼有一個TC39提案定義了一個便利屬性Array.lastItem
來獲取和設置最後一個元素。
其他語言,如Python和Ruby,使用負組索引更容易訪問最後面的元素。例如,可以簡單地使用arr[-1]
替代arr[arr.length-1]
訪問最後一個元素。
使用 Proxy 也可以在 Javascript 中使用負索引。
const negativeArray = els =>
new Proxy(els, {
get: (target, propKey, receiver) =>
Reflect.get(
target,
+propKey < 0 ? String(target.length + +propKey) : propKey,
receiver
)
});
一個重要的註意事項是包含handler.get的陷阱字元串化所有屬性。 對於數組訪問,我們需要將屬性名稱強制轉換為Numbers
,這樣就可以使用一元加運算符簡潔地完成。
現在[-1]
訪問最後一個元素,[-2]
訪問倒數第二個元素,以此類推。
const unicorn = negativeArray(["