全局对象充当顶级词法环境(如果你愿意的话,作用域链的顶部)。这意味着可以通过直接引用(如变量)访问全局属性:
// global code
this.foo = 1; // creating a global property
foo // accessing the global property via a direct reference
这也意味着可以通过属性引用访问全局变量:
// global code
var foo = 1; // creating a global variable
this.foo // accessing the global variable via a property reference
>口译1现在,基于上述信息,似乎可以互换使用术语"全局变量"和"全局属性",这意味着这两个术语表示完全相同的全局绑定集。
但是,使用var
创建的全局变量之间有两个区别,例如var foo = 1;
,以及通过赋值创建的全局属性,例如this.foo = 1;
:
变量是静态作用域的,而全局属性是动态添加到全局环境中的:
foo // => undefined bar // throws ReferenceError var foo = 1; this.bar = 1;
因此,全局变量在程序评估之前绑定,而全局属性在程序评估期间绑定,当分配被评估时。
全局变量是不可配置的,即它们不能被删除(更具体地说,它们相应的绑定随后无法从环境中删除),而通过赋值创建的全局属性是可配置的。
// the names "foo" and "bar" are bound to the global environment var foo = 1; this.bar = 1; // the binding "bar" can be removed from the global environment subsequently delete this.bar; // the binding "foo" cannot be removed subsequently
话虽如此,应该注意的是,可以创建不可配置的全局属性:
Object.defineProperty( this, 'bar', { value: 1 }); // non-configurable by default
<小时 />口译2
现在,基于这些新信息,可以说只有静态范围的全局绑定可以同时称为全局属性和全局变量,而动态添加的全局绑定只是全局属性,而不是全局变量,这意味着术语"全局变量"表示由术语"全局属性"表示的集合的子集, 如:
所有全局变量都是全局属性
只有静态范围的全局属性是全局变量
那么,哪种解释是正确的?这两个术语是表示同一组绑定,还是一个绑定是另一个绑定的子集?
<小时 />问题
我确实理解术语"全局属性" - 全局属性是全局对象的属性。然而,术语"全局变量"似乎含糊不清。有些人将其用作"全局属性"的同义词,而另一些人则将其定义为通过var
语句定义的全局属性。我的问题的目的是确定这两种含义中哪一种是正确的
好吧,您已经知道我所说的区分变量的边缘情况和附加到window
的属性的所有内容。
如果你想变得非常非常迂腐,我想你可以将全局作用域视为一个函数作用域和一个作用域,其中使用与程序中提供的相同的隐藏配置设置使用属性扩展window
对象(例如:vars 可以重新分配但不能删除)。因此,从这个意义上说,就功能而言,它们是不同的,并且反映了全局范围内的属性和变量的属性。
这样称呼他们是完全可以的。
但大多数人甚至没有意识到其中的区别,更不用说区分这两个术语了。
即使是重要的JS作者也提到了通过省略var
来意外设置global variable
,而实际上,JS扩展了函数范围,如果它进入全局范围而没有点击该名称,它会附加一个带有该数据的global property
,而不是global variable
。
但这确实把我们带到了关键 - 一个强大,稳定和可靠的JS应用程序,与其他应用程序一起存在于现代网页上,真的不应该太关心差异。
在这种情况下,目标是使用尽可能少的全局属性和变量。
此外,可变/属性碰撞的危险是相同的,无论它是哪一种。
变量不受delete
的影响,但是任何有用的程序delete
它从未设置过的属性的可能性有多大?
所以就我个人而言,我认为理解边缘情况是件好事,但我也认为,虽然我内心的学究想要同意存在差异,而且它们不是同限的,但我内心的实用主义者想到一个人们正在积极利用全球范围的世界,以至于这对他们有很大的影响,我就不寒而栗。
在这里可以找到一个很好的解释,但我会缩短它来回答你的问题。当你说:
这两个术语表示完全相同的全局绑定集。
。你几乎是对的,但不完全正确。属性赋值(如this.foo = 1
)将保存到全局对象中。但是,像var bar = 2
这样的变量声明会保存到变量对象中。
在全局作用域下执行时,全局对象和变量对象都由同一个对象表示 - 全局对象(在浏览器中执行时,这是window
对象)。
我之所以提到这一点,是因为仅凭您的解释不足以解释该程序的行为:
// "this" refers to the global object. But global object is also acting as the
// variable object! Because of that, the following code works:
var foo = 1;
alert(this.foo); // 1
(function() {
// "this" still refers to the global object! But the *variable* object has
// changed because we're now in the execution context of a function, thus
// the behavior changes:
var bar = 2;
alert(this.foo); // 1
alert(this.bar); // undefined
})();
但是,这并不意味着全局属性和全局变量是相同的。所有属性上都有三个隐藏标志:ReadOnly
、DontEnum
和DontDelete
。
当使用隐式属性声明(如this.foo = 1
)时,DontDelete
属性设置为false
。当你使用变量声明(如var bar = 2
)时,DontDelete
属性设置为true
,因此表示使用delete
运算符时它们之间的差异。
回答你改写的问题:
术语"全局变量"似乎含糊不清。有些人将其用作 "全局财产"的同义词,而其他人则将其定义为全局 通过 var 语句定义的属性。我的意图 问题是确定这两种含义中哪一个是正确的。
该术语没有明确定义,因此您只要求一种意见。
通常,术语"全局属性"在使用语法this.foo = 1
创建变量时使用,术语"全局变量"在使用语法var bar = 2
创建变量时使用。没有什么可讨论的了。
这两个术语都与幕后发生的事情没有真正的关系,因此您能做的最好的事情就是了解幕后实际发生的事情,您已经这样做了。
进一步要求对两个任意术语进行绝对定义只会让你成为一个不受欢迎的人。