function foobar() {}
console.log(typeof window.foobar); // "function"
console.log(typeof window.alert); // "function"
delete window.foobar;
delete window.alert;
console.log(typeof window.foobar); // "function"
console.log(typeof window.alert); // "undefined"
console.log(window.hasOwnProperty('foobar')); // true
console.log(window.hasOwnProperty('alert')); // false
有人可以解释一下,这怎么可能?
为什么我不能简单地删除窗口对象的foobar
属性?
为什么像foobar
这样的自定义全局函数会受delete
运算符的保护,但是alert
之类的内置全局函数不会?
答案 0 :(得分:2)
全局变量不可配置:
Object.getOwnPropertyDescriptor(window, 'foobar').configurable; // false
那是因为根据Static Semantics: TopLevelVarDeclaredNames,函数声明就像var
声明:
在函数或脚本的顶层,内部函数声明 被视为var声明。
并且Runtime Semantics: GlobalDeclarationInstantiation将它们声明为不可配置:
- 对于 functionsToInitialize 中的每个产品 f ,请执行
醇>
- 让状态为 envRec 。CreateGlobalFunctionBinding( fn , fo , false 强>)。
CreateGlobalFunctionBinding (N, V, D)使用参数 false 作为属性的可配置性:
- 醇>
- 让 desc 成为PropertyDescriptor {[[Value]]: V ,[[Writable]]: true ,[[Enumerable] ]: true ,[[Configurable]]: d }。
因此,[[Delete]]使用的delete
operator内部方法不会成功:
如果 desc 。[[Configurable]]为 true ,则
- 从 O 中删除名为 P 的属性。
- 返回 true 。
- 醇>
返回 false 。
这就是你应该使用严格模式的原因。否则,一些问题会被忽略。
delete window.foobar; // false (in sloppy mode)
delete window.foobar; // TypeError (in strict mode)
您可以删除原生alert
,因为它是可配置的。
该方法在HTML spec中定义为IDL方法:
[Global] /*sealed*/ interface Window : EventTarget { // ... void alert(optional DOMString message = ""); };
根据WebIDL,exposed operations如果不是unforgeable则应该是可配置的:
该属性具有{[[Writable]]属性: B ,[[Enumerable]]: true ,[[Configurable]]: B },其中 B false 如果操作是{{3在界面上, true 否则。
Object.getOwnPropertyDescriptor(window, 'alert').configurable; // true
如果您希望能够删除该功能,请将其指定为属性而不是使用函数声明:
window.foobar = function() {};
Object.getOwnPropertyDescriptor(window, 'foobar').configurable; // true
delete window.foobar; // true
那是因为当你通过属性赋值创建属性时,它是可配置的。来自unforgeable的CreateDataProperty,
- 让 newDesc 成为PropertyDescriptor {[[Value]]: V ,[[Writable]]: true ,[[Enumerable] ]: true ,[[Configurable]]: 的真强>}。
醇>