从窗口对象中删除属性时对窗口对象的奇怪行为

时间:2016-07-13 00:38:59

标签: javascript

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之类的内置全局函数不会?

1 个答案:

答案 0 :(得分:2)

全局变量不可配置:

Object.getOwnPropertyDescriptor(window, 'foobar').configurable; // false

那是因为根据Static Semantics: TopLevelVarDeclaredNames,函数声明就像var声明:

  

在函数或脚本的顶层,内部函数声明   被视为var声明。

并且Runtime Semantics: GlobalDeclarationInstantiation将它们声明为不可配置:

  
      
  1. 对于 functionsToInitialize 中的每个产品 f ,请执行      
        
    1. 状态 envRec CreateGlobalFunctionBinding fn fo false )。
    2.   
  2.   

CreateGlobalFunctionBinding (N, V, D)使用参数 false 作为属性的可配置性:

  
      
    1.   
    2. desc 成为PropertyDescriptor {[[Value]]: V ,[[Writable]]: true ,[[Enumerable] ]: true ,[[Configurable]]:    d }。
    3.   
  1.   

因此,[[Delete]]使用的delete operator内部方法不会成功:

  
      
  1. 如果 desc 。[[Configurable]]为 true ,则

         
        
    1. O 中删除名为 P 的属性。
    2.   
    3. 返回 true
    4.   
  2.   
  3. 返回 false

  4.   

这就是你应该使用严格模式的原因。否则,一些问题会被忽略。

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

那是因为当你通过属性赋值创建属性时,它是可配置的。来自unforgeableCreateDataProperty

  
      
  1. newDesc 成为PropertyDescriptor {[[Value]]: V ,[[Writable]]: true ,[[Enumerable] ]: true ,[[Configurable]]:   的}。
  2.