二級(jí)域名著名網(wǎng)站logo網(wǎng)站設(shè)計(jì)
Proxy
是 ES6 引入的一種強(qiáng)大的攔截機(jī)制,用于定義對(duì)象的基本操作(如讀取、賦值、刪除等)的自定義行為。相較于 Object.defineProperty
,Proxy
提供了更靈活、全面的攔截能力。
1. Proxy 語法
const proxy = new Proxy(target, handler);
target
:被代理的對(duì)象handler
:定義攔截行為的對(duì)象
2. Proxy 基本用法
(1) 攔截對(duì)象的屬性訪問
const person = {name: "Alice",age: 25,
};const proxyPerson = new Proxy(person, {get(target, prop) {console.log(`訪問屬性: ${prop}`);return prop in target ? target[prop] : "屬性不存在";},
});console.log(proxyPerson.name); // 訪問屬性: name -> "Alice"
console.log(proxyPerson.gender); // 訪問屬性: gender -> "屬性不存在"
(2) 攔截對(duì)象的屬性修改
const proxyPerson = new Proxy(person, {set(target, prop, value) {if (prop === "age" && typeof value !== "number") {throw new Error("年齡必須是數(shù)字");}target[prop] = value;console.log(`設(shè)置 ${prop} 為 ${value}`);return true;},
});proxyPerson.age = 30; // 設(shè)置 age 為 30
proxyPerson.age = "abc"; // 拋出錯(cuò)誤: 年齡必須是數(shù)字
(3) 攔截對(duì)象的屬性刪除
const proxyPerson = new Proxy(person, {deleteProperty(target, prop) {console.log(`刪除屬性: ${prop}`);return delete target[prop];},
});delete proxyPerson.age; // 刪除屬性: age
(4) 攔截 in 操作符 (has
方法)
const proxyPerson = new Proxy(person, {has(target, prop) {console.log(`檢查屬性是否存在: ${prop}`);return prop in target;},
});console.log("name" in proxyPerson); // 檢查屬性是否存在: name -> true
console.log("gender" in proxyPerson); // 檢查屬性是否存在: gender -> false
const range = { start: 10, end: 50 };const proxy = new Proxy(range, {has(target, prop) {return prop >= target.start && prop <= target.end;}
});console.log(15 in proxy); // true
console.log(60 in proxy); // false
(5) 攔截函數(shù)調(diào)用 (apply
方法)
const multiply = new Proxy((a, b) => a * b, {apply(target, thisArg, args) {console.log(`調(diào)用函數(shù) multiply,參數(shù): ${args}`);return target(...args);}
});console.log(multiply(3, 4)); // 調(diào)用函數(shù) multiply,參數(shù): 3,4 -> 12
(6) 攔截構(gòu)造函數(shù) (construct
方法)
const Person = new Proxy(class {constructor(name) {this.name = name;}
}, {construct(target, args) {console.log(`創(chuàng)建實(shí)例,參數(shù): ${args}`);return new target(...args);}
});const user = new Person("Alice"); // 創(chuàng)建實(shí)例,參數(shù): Alice
特點(diǎn):
- 可以 監(jiān)聽整個(gè)對(duì)象,而不是單個(gè)屬性。
- 能攔截 所有操作(如
get
、set
、has
、deleteProperty
、apply
等)。 - 可以用于 動(dòng)態(tài)代理,使得代碼更具擴(kuò)展性。
3. Proxy 實(shí)際使用場(chǎng)景
(1) 數(shù)據(jù)驗(yàn)證和格式化
const user = new Proxy({}, {set(target, prop, value) {if (prop === "age" && typeof value !== "number") {throw new Error("年齡必須是數(shù)字");}target[prop] = value;return true;}
});
(2) 實(shí)現(xiàn)私有屬性和方法
const createUser = () => {const privateData = new WeakMap();return new Proxy({}, {get(target, prop) {if (prop.startsWith("_")) {throw new Error("無法訪問私有屬性");}return target[prop];}});
};
(3) 添加日志記錄和調(diào)試功能
const logger = new Proxy({}, {get(target, prop) {console.log(`訪問屬性: ${prop}`);return target[prop];}
});
(4) 提供默認(rèn)值和只讀訪問
const defaultSettings = new Proxy({}, {get(target, prop) {return prop in target ? target[prop] : "默認(rèn)值";},set() {throw new Error("設(shè)置操作被禁止");}
});
(5) 實(shí)現(xiàn)惰性加載和緩存
const lazyObject = new Proxy({}, {get(target, prop) {if (!(prop in target)) {console.log(`初始化 ${prop}`);target[prop] = prop.toUpperCase();}return target[prop];}
});
(6) 解決 this
指向問題
const obj = {name: "Alice",greet() {return `Hello, ${this.name}`;}
};const proxyObj = new Proxy(obj, {get(target, prop, receiver) {return typeof target[prop] === "function" ? target[prop].bind(target) : target[prop];}
});const greet = proxyObj.greet;
console.log(greet()); // Hello, Alice
4.Object.defineProperty
Object.defineProperty()
允許直接在對(duì)象上定義新的屬性,或者修改已有屬性的特性(如可讀寫性、是否可枚舉等)。
示例:
const person = {};Object.defineProperty(person, "name", {value: "Alice",writable: false, // 不能修改enumerable: true,configurable: false
});console.log(person.name); // Alice
person.name = "Bob"; // 失敗,嚴(yán)格模式下會(huì)報(bào)錯(cuò)
console.log(person.name); // Alice
特點(diǎn):
- 只能加工 單個(gè)屬性,不能監(jiān)聽整個(gè)對(duì)象。
- 只能 定義靜態(tài)的行為,不能動(dòng)態(tài)處理對(duì)象屬性的操作。
- 不能攔截 刪除、新增屬性 或 函數(shù)調(diào)用。
5. Proxy
與 Object.defineProperty
詳細(xì)對(duì)比
特性 | Object.defineProperty | Proxy |
---|---|---|
監(jiān)聽屬性讀取 | ? 不支持 | ? 支持 (get ) |
監(jiān)聽屬性賦值 | ? 支持 (set ) | ? 支持 (set ) |
監(jiān)聽屬性刪除 | ? 不支持 | ? 支持 (deleteProperty ) |
監(jiān)聽屬性存在性 | ? 不支持 | ? 支持 (has ) (in 關(guān)鍵字) |
監(jiān)聽對(duì)象新增屬性 | ? 不支持 | ? 支持 (set ) |
監(jiān)聽函數(shù)調(diào)用 | ? 不支持 | ? 支持 (apply ) |
監(jiān)聽構(gòu)造函數(shù) | ? 不支持 | ? 支持 (construct ) |
監(jiān)聽整個(gè)對(duì)象 | ? 需要對(duì)每個(gè)屬性定義 | ? 一次性監(jiān)聽整個(gè)對(duì)象 |
適用于數(shù)組或集合 | ? 不適合 | ? 適合 |
可擴(kuò)展性 | ? 需手動(dòng)定義 | ? 更強(qiáng)大,支持代理嵌套 |