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

delete: can someone explain this behavior

本文关键字:解释 删除      更新时间:2023-09-26

比较此代码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

在这里查看它的实际效果

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

这能解释吗?

1 代码不能在Chrome控制台或Firebug中测试,也不能在JSFIDDLE中测试。在这些环境中,所有代码都是evalled的,而在邪恶的代码中,delete处理任何eval的结果(请参阅更多内容)。在IE <9中,无论如何都不允许使用delete window[anything]

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

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

在第二个块中,someVar 是全局执行上下文 的变量上下文绑定对象的属性 — 这也是window 。不能删除绑定对象作为绑定对象的角色接收的属性(即使可以通过其他方式删除它接收的属性)。也就是说,您不能删除用 var 声明的变量(以及以相同方式添加的其他一些内容)。

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

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

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

  1. this 设置为指向调用指定的对象(this的值通常是隐式设置的,但有一些方法可以显式设置它)。
  2. 为此调用创建执行上下文
  3. 为该执行上下文创建变量上下文
  4. 为该变量上下文创建绑定对象
  5. 将函数的名称(如果有)作为引用函数的属性添加到绑定对象中。
  6. arguments 属性添加到绑定对象,引用函数的参数伪数组。
  7. 将函数定义中声明的任何命名参数添加为绑定对象的属性,并引用其在参数中的条目。
  8. 添加通过 var 语句(函数体中的任何位置)声明的任何变量的名称作为绑定对象的属性,最初值为 undefined
  9. 如果在函数中声明了命名函数,请将其名称添加为绑定对象的属性,并引用这些函数。
  10. 将绑定对象放在作用域链的顶部(详见下文)。

。然后开始逐步执行函数主体中的代码。任何带有初始值设定项(例如,var a = 5;而不仅仅是var a;var语句在执行点到达它们时都被视为赋值语句(a = 5;)。

在上述内容中,每当将属性添加到"绑定对象"时,都会添加一个标志,指示无法删除该属性。这就是为什么不能删除var(以及声明的函数的名称等)的原因。

任何非限定引用都通过作用域链进行查找。因此,当您在代码中引用a时,解释器首先查找的是作用域链顶部的绑定对象。如果它有一个名为 a 的属性,那就是使用的;如果没有,我们查看作用域链下的下一个链接,并在找到该属性时使用该属性;依此类推,直到我们用完作用域链上的链接。全局对象是该链的最底层环节(这就是全局变量工作的原因)。

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

  1. 为此调用创建执行上下文
  2. 为该执行上下文创建变量上下文
  3. 为该变量上下文创建绑定对象
  4. this设置为指向绑定对象;这使它成为全局对象。
  5. 根据环境的定义在该对象上设置一些默认属性(例如,在浏览器中,属性window被添加到对象中,引用自身)。

。然后我们基本上从函数中的步骤 8 开始:

  • 添加通过 var 语句声明的任何变量的名称(全局范围内的任何位置)作为绑定/全局对象的属性,最初值为 undefined
  • 如果在全局范围内声明了命名函数,请将其名称添加为绑定/全局对象的属性,并引用这些函数。
  • 将绑定/全局对象放在作用域链的顶部(更多内容见下文)。

。并开始逐步执行代码(再次将var初始值设定项变为赋值项)。