JavaScript的Proxy對象是一種強大且靈活的特性,它允許你攔截并自定義對對象執行的操作。自ECMAScript 6(ES6)引入以來,Proxy對象為控制對象的基本操作行為提供了一種機制,使進階用例和改進的安全性成為可能。
代理對象的基礎
一個Proxy是由兩個主要元件建立的:目标對象和處理器。目标對象是你想攔截操作的原始對象,處理器是一個包含名為陷阱的方法的對象,這些方法定義了這些操作的自定義行為。
建立一個Proxy
const targetObject = {
name: 'John',
age: 25,
};
const handler = {
get(target, prop) {
console.log(`擷取屬性 ${prop}`);
return target[prop];
},
};
const proxy = new Proxy(targetObject, handler);
console.log(proxy.name); // 輸出: 擷取屬性 name, John
在這個例子中,get陷阱攔截屬性通路并在傳回實際屬性值之前記錄一條消息。
了解目标、屬性和值
- 目标(Target):目标是Proxy包裹的原始對象。在上面的例子中,targetObject就是目标。
- 屬性(Prop):屬性表示對象上被通路的屬性。在get陷阱中,prop是被通路的屬性的名稱。
- 值(Value):值指的是賦給屬性的值。在set陷阱中,value是被賦給屬性的新值。
常見的處理器方法
- get(target, prop, receiver):get陷阱攔截屬性通路,并允許你自定義讀取屬性時的行為。
- set(target, prop, value, receiver):set陷阱攔截屬性指派,并使你能夠驗證或修改被賦的值。
- has(target, prop):has陷阱在使用in操作符檢查屬性是否存在時觸發。
- deleteProperty(target, prop):deleteProperty陷阱在使用delete操作符删除屬性時被調用。
- apply(target, thisArg, argumentsList):apply陷阱在Proxy作為函數調用時被觸發。
代理對象的應用場景
1. 資料驗證
使用代理對象可以通過驗證或修改屬性值來強制執行資料限制。
const validatedUser = new Proxy({}, {
set(target, prop, value) {
if (prop === 'age' && (typeof value !== 'number' || value < 0 || value > 120)) {
throw new Error('無效的年齡');
}
target[prop] = value;
return true;
},
});
validatedUser.age = 30; // 有效指派
validatedUser.age = -5; // 抛出錯誤: 無效的年齡
2. 日志記錄
代理對象可以輕松記錄屬性通路情況,為調試或性能監控提供見解。
const loggedObject = new Proxy({}, {
get(target, prop) {
console.log(`通路屬性: ${prop}`);
return target[prop];
},
});
loggedObject.name = 'Alice'; // 通路屬性: name
console.log(loggedObject.name); // 通路屬性: name
3. 安全性
代理對象可以通過防止未授權的屬性通路或操作來增強對象安全性。
const securedObject = new Proxy({ secret: 'classified' }, {
get(target, prop) {
if (prop === 'secret') {
throw new Error('未授權的通路');
}
return target[prop];
},
});
console.log(securedObject.publicInfo); // 通路允許
console.log(securedObject.secret); // 抛出錯誤: 未授權的通路
4. 記憶化
代理對象可用于記憶化,緩存耗時的函數調用結果以提高性能。
function fibonacci(n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
const memoizedFibonacci = new Proxy({}, {
get(target, prop) {
if (!(prop in target)) {
target[prop] = fibonacci(Number(prop));
}
return target[prop];
},
});
console.log(memoizedFibonacci[10]); // 計算并緩存
console.log(memoizedFibonacci[5]); // 從緩存中擷取
實戰示例:電商場景
考慮一個電商場景,你想使用代理對象來強制執行某些業務規則。
const product = {
name: 'Smartphone',
price: 500,
quantity: 10,
};
const securedProduct = new Proxy(product, {
set(target, prop, value) {
if (prop === 'quantity' && value < 0) {
throw new Error('無效的數量');
}
target[prop] = value;
return true;
},
});
securedProduct.quantity = 15; // 有效指派
securedProduct.quantity = -5; // 抛出錯誤: 無效的數量
在這個例子中,Proxy確定産品的數量不能被設定為負值,進而在電商上下文中執行了一個業務規則。
結束
JavaScript Proxy對象為建立動态和可定制的對象行為提供了一個多功能工具。無論是用于資料驗證、日志記錄、安全性還是性能優化,代理對象都為開發者提供了對對象互動的細粒度控制。了解并利用Proxy對象可以在各種實際場景中編寫出更幹淨、可維護和安全的代碼。