比较此代码 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-console或firebug中测试,也不能在jsfiddle中测试。在这些环境中,所有代码均为evalled
,并且在评估代码中delete
适用于由eval
生成的任何内容(请参阅more about that)。在IE<无论如何都不允许9 delete window[anything]
。
答案 0 :(得分:11)
您所看到的是这样一个事实:全局对象(window
,在浏览器上)是两个不同事物的混合,除了全局执行上下文之外,它们在任何地方都是不同的。
在第一个块中,someVar
是window
对象的普通属性。可以通过delete
删除属性。
在第二个块中,someVar
是全局执行上下文的变量上下文的绑定对象的属性 - 也是{{1 }}。您无法删除绑定对象在其作为绑定对象的角色中接收的属性(即使您可以删除以其他方式接收的属性)。也就是说,你不能删除用window
声明的变量(以及其他一些以相同方式添加的东西)。
(对不起,不是我的术语;它来自the spec,确实有一些非常有趣的语言。)
这只是全局执行上下文,我们将这些概念混合在一起。其他执行上下文(例如函数调用)的变量绑定对象仍然是一个非常真实的东西(对于闭包的正常运行至关重要),但是没有直接访问它的编程方式。但是,在全局执行上下文中,它是全局对象,当然我们可以访问它。
如果我们首先查看函数,然后查看全局执行上下文,这有助于理解这一点。当你调用一个函数时,会发生以下事情:
var
设置为指向调用指定的对象(this
的值通常是隐式设置的,但有多种方法可以明确设置它。)this
属性添加到绑定对象,引用该函数的伪参数数组。arguments
语句(函数体中的任何)声明的任何变量的名称作为绑定对象的属性,最初使用值var
。< / LI>
...然后开始逐步执行函数体中的代码。当执行点到达时,任何带有初始值设定项的undefined
语句(例如var
而非var a = 5;
都被视为赋值语句(var a;
)。
在上文中,只要将属性“添加到绑定对象”,就会添加一个表示无法删除的标志。这就是为什么a = 5;
(以及声明的函数的名称等)无法删除的原因。
通过范围链查找任何不合格的引用。因此,当您在代码中引用var
时,解释器看起来的第一个位置是作用域链顶部的绑定对象。如果它有一个名为a
的属性,那就是使用它;如果没有,我们会查看范围链中的下一个链接,并在找到它时使用该属性;等等,直到我们用完范围链上的链接。全局对象是该链的最底层链接(这就是全局变量起作用的原因)。
那么全球背景有什么不同?嗯,实际上很少。这是序列(大致):
a
设置为指向绑定对象;这使它成为全球对象。this
被添加到对象中,引用自身)。...然后我们基本上接受了函数中的第8步:
window
语句(全局范围内的 where )声明的任何变量的名称作为绑定/全局对象的属性,最初使用值var
...并开始逐步执行代码(再次使用undefined
初始化程序成为分配)。