为什么代理中的 set() 陷阱有时会触发 TypeError 而有时不会(均在无效写入操作之后)?
Why do set() traps in proxies sometimes trigger a TypeError and sometimes not (both after an invalid write operation)?
tl;dr:我发现有时在代理的 set() 陷阱中 returning false
不会触发任何 TypeError
,并且有时确实如此。为什么会这样?
据我了解,代理中的 set() 陷阱必须 return true
或 false
来表示是否允许写入操作。如果 false
被 returned,那么应该触发 TypeError
.
然而,这并不总是发生。看看这两个例子:
示例 1(无效,但没有 TypeError)
let page = { currentPage: "Home" };
page = new Proxy(page, {
set(target, property, value) {
if (typeof value !== "string") return false;
//... additional validation logic could be here
target[property] = value;
return true;
}
});
// Attempt an invalid operation:
page.currentPage = 123;
console.log(page.currentPage); // currentPage is still "Home"
// (writing didn't work, but it didn't trigger any TypeError to let me know!)
示例 2(无效,并抛出 TypeError)
(示例取自 javascript.info)
let numbers = [];
numbers = new Proxy(numbers, { // (*)
set(target, property, value) { // to intercept property writing
if (typeof val == 'number') {
target[prop] = val;
return true;
} else {
return false;
}
}
});
numbers.push(1); // added successfully
numbers.push(2); // added successfully
console.log("Length is: " + numbers.length); // 2
// Attempt an invalid operation:
numbers.push("test"); // TypeError ('set' on proxy returned false)
alert("This line is never reached (error in the line above)");
无效的集合操作不起作用(如预期的那样),但为什么我有时会收到 TypeError 而有时不会?理想情况下,我希望总是得到一个错误,这样我就可以快速发现并纠正我的错误。每当我在 set() 陷阱中 return false 时,手动抛出错误的唯一解决方法是什么?
非常感谢您的帮助或见解。
您需要使用严格模式从失败中获取异常 setter。在马虎模式下,赋值运算符直接忽略了这个问题。
(function(){
"use strict";
const page = new Proxy({ currentPage: "Home" }, {
set(target, property, value) {
if (typeof value !== "string") return false;
//... additional validation logic could be here
target[property] = value;
return true;
}
});
page.currentPage = 123; // TypeError, as expected
console.log(page.currentPage);
})();
从 set
陷阱返回 false
只会在执行分配的代码在严格模式下运行时触发错误。在非严格模式下,false
会阻止赋值但不会出现错误。
在您的第一段代码中,代码仅在非严格模式下运行。如果将其修改为严格,则会得到 TypeError:
"use strict";
let page = { currentPage: "Home" };
page = new Proxy(page, {
set(target, property, value) {
if (typeof value !== "string") return false;
//... additional validation logic could be here
target[property] = value;
return true;
}
});
// Attempt an invalid operation:
page.currentPage = 123;
console.log(page.currentPage); // currentPage is still "Home"
// (writing didn't work, but it didn't trigger any TypeError to let me know!)
不同的函数或方法可能 运行 是否为严格模式:
let obj = new Proxy(
{ foo: "hello" },
{ set() { return false; } }
);
function nonStrict(x) {
x.foo = 2;
}
function strict(x) {
"use strict";
x.foo = 2;
}
nonStrict(obj); // OK
console.log(obj); // { foo: "hello" }
strict(obj); // Error
console.log(obj);
在第二个代码块中,.push()
方法进行了写入。该方法显然在严格模式下运行,这就是为什么在尝试写入数组索引时出现 TypeError 的原因。
所有 classes(以及其他 ES6+ 构造,如生成器、模块等)自动处于严格模式:
class Foo {
foo = "hello";
change() {
this.foo = "world";
}
};
const plain = new Foo();
plain.change(); // OK
console.log(plain); // { foo: "world" }
let proxy = new Proxy(
new Foo(),
{ set() { return false; } }
);
proxy.change(); // Error
console.log(proxy);
数组被认为是 class,因此它的方法是严格的。
const arrayLike = { length: 0 };
Array.prototype.push.call(arrayLike, "hello");
console.log(arrayLike); // { 0: "hello", length: 1 }
let proxy = new Proxy(
arrayLike,
{ set() { return false; } }
);
Array.prototype.push.call(proxy, "world"); // Error
console.log(arrayLike);
tl;dr:我发现有时在代理的 set() 陷阱中 returning false
不会触发任何 TypeError
,并且有时确实如此。为什么会这样?
据我了解,代理中的 set() 陷阱必须 return true
或 false
来表示是否允许写入操作。如果 false
被 returned,那么应该触发 TypeError
.
然而,这并不总是发生。看看这两个例子:
示例 1(无效,但没有 TypeError)
let page = { currentPage: "Home" };
page = new Proxy(page, {
set(target, property, value) {
if (typeof value !== "string") return false;
//... additional validation logic could be here
target[property] = value;
return true;
}
});
// Attempt an invalid operation:
page.currentPage = 123;
console.log(page.currentPage); // currentPage is still "Home"
// (writing didn't work, but it didn't trigger any TypeError to let me know!)
示例 2(无效,并抛出 TypeError) (示例取自 javascript.info)
let numbers = [];
numbers = new Proxy(numbers, { // (*)
set(target, property, value) { // to intercept property writing
if (typeof val == 'number') {
target[prop] = val;
return true;
} else {
return false;
}
}
});
numbers.push(1); // added successfully
numbers.push(2); // added successfully
console.log("Length is: " + numbers.length); // 2
// Attempt an invalid operation:
numbers.push("test"); // TypeError ('set' on proxy returned false)
alert("This line is never reached (error in the line above)");
无效的集合操作不起作用(如预期的那样),但为什么我有时会收到 TypeError 而有时不会?理想情况下,我希望总是得到一个错误,这样我就可以快速发现并纠正我的错误。每当我在 set() 陷阱中 return false 时,手动抛出错误的唯一解决方法是什么?
非常感谢您的帮助或见解。
您需要使用严格模式从失败中获取异常 setter。在马虎模式下,赋值运算符直接忽略了这个问题。
(function(){
"use strict";
const page = new Proxy({ currentPage: "Home" }, {
set(target, property, value) {
if (typeof value !== "string") return false;
//... additional validation logic could be here
target[property] = value;
return true;
}
});
page.currentPage = 123; // TypeError, as expected
console.log(page.currentPage);
})();
从 set
陷阱返回 false
只会在执行分配的代码在严格模式下运行时触发错误。在非严格模式下,false
会阻止赋值但不会出现错误。
在您的第一段代码中,代码仅在非严格模式下运行。如果将其修改为严格,则会得到 TypeError:
"use strict";
let page = { currentPage: "Home" };
page = new Proxy(page, {
set(target, property, value) {
if (typeof value !== "string") return false;
//... additional validation logic could be here
target[property] = value;
return true;
}
});
// Attempt an invalid operation:
page.currentPage = 123;
console.log(page.currentPage); // currentPage is still "Home"
// (writing didn't work, but it didn't trigger any TypeError to let me know!)
不同的函数或方法可能 运行 是否为严格模式:
let obj = new Proxy(
{ foo: "hello" },
{ set() { return false; } }
);
function nonStrict(x) {
x.foo = 2;
}
function strict(x) {
"use strict";
x.foo = 2;
}
nonStrict(obj); // OK
console.log(obj); // { foo: "hello" }
strict(obj); // Error
console.log(obj);
在第二个代码块中,.push()
方法进行了写入。该方法显然在严格模式下运行,这就是为什么在尝试写入数组索引时出现 TypeError 的原因。
所有 classes(以及其他 ES6+ 构造,如生成器、模块等)自动处于严格模式:
class Foo {
foo = "hello";
change() {
this.foo = "world";
}
};
const plain = new Foo();
plain.change(); // OK
console.log(plain); // { foo: "world" }
let proxy = new Proxy(
new Foo(),
{ set() { return false; } }
);
proxy.change(); // Error
console.log(proxy);
数组被认为是 class,因此它的方法是严格的。
const arrayLike = { length: 0 };
Array.prototype.push.call(arrayLike, "hello");
console.log(arrayLike); // { 0: "hello", length: 1 }
let proxy = new Proxy(
arrayLike,
{ set() { return false; } }
);
Array.prototype.push.call(proxy, "world"); // Error
console.log(arrayLike);