使用 deleteProperty 陷阱函数避免属性被删除
delete 运算符能够从指定对象上删除一个属性,在删除成功时返回 true,否则返回 false。如果试图用 delete 运算符去删除一个不可配置的属性,在严格模式下将会抛出错误;而非严格模式下只是单纯返回 false。这里有个例子:
let target = {
name: "target",
value: 42
};
Object.defineProperty(target, "name", { configurable: false });
console.log("value" in target); // true
let result1 = delete target.value;
console.log(result1); // true
console.log("value" in target); // false
// Note: The following line throws an error in strict mode
let result2 = delete target.name;
console.log(result2); // false
console.log("name" in target); // true
这里使用了 delete 运算符删除了 value 属性,因此在第三行代码的 console.log() 调用中,使用 in 操作符检测该属性会得到 false。name 属性是不可配置的,因此对其使用 delete 操作符只会返回 false 而不能删除该属性(如果代码运行在严格模式下,则会抛出错误)。你可以在代理对象中使用 deleteProperty 陷阱函数以改变这种行为。
deleteProperty 陷阱函数会在使用 delete 运算符去删除对象属性时下被调用, 并且会被传入两个参数:
-
trapTarget:需要删除属性的对象(即代理的目标对象);
-
key:需要删除的属性的键(字符串类型或符号类型)。
Reflect.deleteProperty() 方法也接受这两个参数,并提供了 deleteProperty 陷阱函数的默认实现。你可以结合 Reflect.deleteProperty() 方法以及 deleteProperty 陷阱函数,来修改 delete 运算符的行为。例如,能确保 value 属性不被删除:
let target = {
name: "target",
value: 42
};
let proxy = new Proxy(target, {
deleteProperty(trapTarget, key) {
if (key === "value") {
return false;
} else {
return Reflect.deleteProperty(trapTarget, key);
}
}
});
// Attempt to delete proxy.value
console.log("value" in proxy); // true
let result1 = delete proxy.value;
console.log(result1); // false
console.log("value" in proxy); // true
// Attempt to delete proxy.name
console.log("name" in proxy); // true
let result2 = delete proxy.name;
console.log(result2); // true
console.log("name" in proxy); // false
这段代码与 has 陷阱函数的例子相似,在 deleteProperty 陷阱函数中检查 key 的值是否为 "value"。如果是,返回 false;否则通过调用 Reflect.deleteProperty() 方法来进行默认的操作。value 属性是不能被删除的,因为该操作被 proxy 对象拦截;而 name 则能如期被删除。这么做允许你在严格模式下保护属性避免其被删除,并且不会抛出错误。