删除:有人可以解释这种行为

时间:2011-05-13 08:44:44

标签: javascript operators

比较此代码 1

  somevar = 5;
  delete window.somevar;
  alert(typeof somevar) //=> undefined, so deleted

到此代码:

  var somevar = 5;
  delete window.somevar;
  alert(typeof somevar) //=> number, so NOT deleted

See it in action here

现在在第一个区块中,somevar被删除,而在第二个区块中则没有。唯一的区别是在第二个块中使用var关键字。两个块都在全局范围内运行。

可以解释一下吗?

1 代码无法在chrome-console或firebug中测试,也不能在jsfiddle中测试。在这些环境中,所有代码均为evalled,并且在评估代码中delete适用于由eval生成的任何内容(请参阅more about that)。在IE<无论如何都不允许9 delete window[anything]

1 个答案:

答案 0 :(得分:11)

您所看到的是这样一个事实:全局对象(window,在浏览器上)是两个不同事物的混合,除了全局执行上下文之外,它们在任何地方都是不同的。

在第一个块中,someVarwindow对象的普通属性。可以通过delete删除属性。

在第二个块中,someVar是全局执行上下文的变量上下文绑定对象的属性 - 也是{{1 }}。您无法删除绑定对象在其作为绑定对象的角色中接收的属性(即使您可以删除以其他方式接收的属性)。也就是说,你不能删除用window声明的变量(以及其他一些以相同方式添加的东西)。

(对不起,不是我的术语;它来自the spec,确实有一些非常有趣的语言。)

这只是全局执行上下文,我们将这些概念混合在一起。其他执行上下文(例如函数调用)的变量绑定对象仍然是一个非常真实的东西(对于闭包的正常运行至关重要),但是没有直接访问它的编程方式。但是,在全局执行上下文中,它是全局对象,当然我们可以访问它。

如果我们首先查看函数,然后查看全局执行上下文,这有助于理解这一点。当你调用一个函数时,会发生以下事情:

  1. var设置为指向调用指定的对象(this的值通常是隐式设置的,但有多种方法可以明确设置它。)
  2. 为此次通话创建执行上下文
  3. 为该执行上下文创建变量上下文
  4. 为该变量上下文创建绑定对象
  5. 将函数的名称(如果有)添加到绑定对象作为引用该函数的属性。
  6. this属性添加到绑定对象,引用该函数的伪参数数组。
  7. 将在函数定义中声明的任何命名参数添加为绑定对象的属性,并在参数中引用它们的条目。
  8. 添加通过arguments语句(函数体中的任何)声明的任何变量的名称作为绑定对象的属性,最初使用值var。< / LI>
  9. 如果在函数中声明了命名函数,请将它们的名称添加为绑定对象的属性,并参考这些函数。
  10. 将绑定对象放在范围链的顶部(更多信息如下)。
  11. ...然后开始逐步执​​行函数体中的代码。当执行点到达时,任何带有初始值设定项的undefined语句(例如var而非var a = 5;都被视为赋值语句(var a;)。

    在上文中,只要将属性“添加到绑定对象”,就会添加一个表示无法删除的标志。这就是为什么a = 5;(以及声明的函数的名称等)无法删除的原因。

    通过范围链查找任何不合格的引用。因此,当您在代码中引用var时,解释器看起来的第一个位置是作用域链顶部的绑定对象。如果它有一个名为a的属性,那就是使用它;如果没有,我们会查看范围链中的下一个链接,并在找到它时使用该属性;等等,直到我们用完范围链上的链接。全局对象是该链的最底层链接(这就是全局变量起作用的原因)。

    那么全球背景有什么不同?嗯,实际上很少。这是序列(大致):

    1. 为此次通话创建执行上下文
    2. 为该执行上下文创建变量上下文
    3. 为该变量上下文创建绑定对象
    4. a设置为指向绑定对象;这使它成为全球对象。
    5. 根据环境定义在该对象上设置一些默认属性(例如,在浏览器中,属性this被添加到对象中,引用自身)。
    6. ...然后我们基本上接受了函数中的第8步:

      • 添加通过window语句(全局范围内的 where )声明的任何变量的名称作为绑定/全局对象的属性,最初使用值var
      • 如果在全局范围内声明了命名函数,请将它们的名称添加为绑定/全局对象的属性,并引用这些函数。
      • 将绑定/全局对象放在范围链的顶部(更多信息如下)。

      ...并开始逐步执​​行代码(再次使用undefined初始化程序成为分配)。