JavaScript - 代理:初學者指南
Hello there, aspiring programmers! Today, we're going to embark on an exciting journey into the world of JavaScript Proxies. Don't worry if you've never heard of them before – we'll start from the very basics and work our way up. By the end of this tutorial, you'll be well-versed in the art of using Proxies like a pro!
什麼是 JavaScript 中的代理?
讓我們從一個簡單的比喻開始。想像你是一位名人(因為為什麼不夢想大一些呢?),你非常出名,需要有人來處理你的約會、粉絲信和其他日常活動。在現實世界中,這個代表你行事的人稱為代理。
在 JavaScript 中,代理的工作方式與此類似。它是一個包絡另一個對象(我們稱之為目標對象)的對象,並可以截獲和重新定義該對象的基本操作。酷炫吧?
以下是一個基本示例來讓我們開始:
let target = {
name: "John Doe",
age: 30
};
let handler = {
get: function(target, property) {
console.log(`Getting the ${property} property`);
return target[property];
}
};
let proxy = new Proxy(target, handler);
console.log(proxy.name);
如果你運行這段代碼,你會看到:
Getting the name property
John Doe
讓我們分解一下:
- 我們有一個帶有
name
和age
屬性的target
對象。 - 我們創建一個帶有
get
拦截器(我們稍後會更多談論拦截器)的handler
對象。 - 我們使用
Proxy
构造函数創建一個proxy
,傳入我們的target
和handler
。 - 當我們嘗試訪問
proxy.name
時,我們的get
拦截器被觸發,在返回實際值之前記錄一條消息。
JavaScript 代理处理器
現在我們已經略嘗勝味,讓我們更深入地研究一下代理处理器。处理器是一個定義了我們代理的拦截器的對象。拦截器是提供屬性查找、賦值、枚舉、函數調用等方法的方法。
以下是一些常見的处理器拦截器表格:
拦截器 | 描述 |
---|---|
get | 截獲屬性訪問 |
set | 截獲屬性賦值 |
has | 截獲 in 運算符 |
deleteProperty | 截獲 delete 運算符 |
apply | 截獲函數調用 |
construct | 截獲 new 運算符 |
讓我們看一下一個使用多個拦截器的更全面的示例:
let target = {
name: "Alice",
age: 25
};
let handler = {
get: function(target, property) {
console.log(`Accessing the ${property} property`);
return target[property];
},
set: function(target, property, value) {
console.log(`Setting the ${property} property to ${value}`);
target[property] = value;
return true;
},
has: function(target, property) {
console.log(`Checking if ${property} exists`);
return property in target;
}
};
let proxy = new Proxy(target, handler);
console.log(proxy.name); // Triggers get trap
proxy.job = "Developer"; // Triggers set trap
console.log("age" in proxy); // Triggers has trap
運行這段代碼將輸出:
Accessing the name property
Alice
Setting the job property to Developer
Checking if age exists
true
這不是很棒嗎?我們的代理現在正在截獲屬性訪問、賦值和 in
運算符!
JavaScript 代理對象的使用
你可能會想,"這很酷,但我在什麼時候會真正使用這個?" 好問題!代理在以下幾個實際應用中非常有用:
- 驗證:你可以使用代理在數據設置到對象上之前進行驗證。
let user = {
name: "Bob",
age: 30
};
let validator = {
set: function(obj, prop, value) {
if (prop === "age") {
if (typeof value !== "number") {
throw new TypeError("Age must be a number");
}
if (value < 0 || value > 120) {
throw new RangeError("Age must be between 0 and 120");
}
}
obj[prop] = value;
return true;
}
};
let proxiedUser = new Proxy(user, validator);
proxiedUser.age = 25; // This works
try {
proxiedUser.age = "thirty"; // This throws a TypeError
} catch (e) {
console.log(e.message);
}
try {
proxiedUser.age = 150; // This throws a RangeError
} catch (e) {
console.log(e.message);
}
- 日誌記錄:你可以使用代理來記錄對象屬性的訪問。
let target = {
name: "Charlie",
age: 35
};
let logger = {
get: function(target, property) {
console.log(`Property ${property} accessed at ${new Date()}`);
return target[property];
}
};
let proxiedTarget = new Proxy(target, logger);
console.log(proxiedTarget.name);
console.log(proxiedTarget.age);
- 默認值:你可以使用代理為不存在的屬性提供默認值。
let handler = {
get: function(target, property) {
return property in target ? target[property] : "Property not found";
}
};
let proxy = new Proxy({}, handler);
proxy.name = "David";
console.log(proxy.name); // Outputs: David
console.log(proxy.age); // Outputs: Property not found
JavaScript 代理处理器列表
讓我們結束我們對 JavaScript 代理的探索,看一下所有可用的处理器拦截器列表:
处理器拦截器 | 描述 |
---|---|
get | 截獲獲取屬性值 |
set | 截獲設置屬性值 |
has | 截獲 in 運算符 |
deleteProperty | 截獲 delete 運算符 |
apply | 截獲函數調用 |
construct | 截獲 new 運算符 |
getPrototypeOf | 截獲 Object.getPrototypeOf
|
setPrototypeOf | 截獲 Object.setPrototypeOf
|
isExtensible | 截獲 Object.isExtensible
|
preventExtensions | 截獲 Object.preventExtensions
|
getOwnPropertyDescriptor | 截獲 Object.getOwnPropertyDescriptor
|
defineProperty | 截獲 Object.defineProperty
|
ownKeys | 截獲 Object.getOwnPropertyNames 和 Object.getOwnPropertySymbols
|
就这样!我們已經介紹了 JavaScript 代理的基本知識,探索了一些實際用途,甚至還看過所有可用的处理器拦截器。記住,像任何强大的工具一樣,代理應該謹慎使用。它們在某些使用場景中非常有用,但它們確實會帶來性能開銷。
希望這個教程能夠幫助你解開 JavaScript 代理的神秘面紗。持續練習,持續編程,在你知曉之前,你會變得像專家一樣使用代理!快樂編程!
Credits: Image by storyset