10

全局对象充当顶级词法环境(范围链的顶部,如果您愿意的话)。这意味着可以通过直接引用(如变量)访问全局属性:

// 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但是,使用,eg创建的全局变量var foo = 1;和通过赋值创建的全局属性之间有两个区别,例如this.foo = 1;

  1. 全局变量是静态作用域的,而全局属性是动态添加到全局环境中的:

    foo // => undefined
    bar // throws ReferenceError
    
    var foo = 1;
    this.bar = 1;
    

    因此,全局变量在程序评估之前绑定,而全局属性在程序评估期间绑定,当赋值被评估时。

  2. 全局变量是不可配置的,即它们不能被删除(更具体地说,它们对应的绑定随后不能从环境中删除),而通过赋值创建的全局属性是可配置的。

    // 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语句定义的全局属性。我的问题的目的是确定这两种含义中的哪一种是正确的

4

2 回答 2

5

好吧,你已经知道我会说的所有东西来区分变量的边缘情况和附加到window.

如果您想变得非常非常迂腐,我想您可以将全局范围视为功能范围window使用与程序中提供的相同隐藏配置设置的属性扩展对象的范围(例如: vars 可以重新分配但不能删除)。所以从这个意义上说,就功能而言,它们是不同的,并且反映了全局范围内的属性和变量的属性。

并且这样称呼它们是完全可以的。
但是那里的大多数人甚至没有认识到差异,更不用说区分这两个术语了。
即使是重要的 JS 作者也提到了global variable通过省略 来意外设置 a ,var实际上,JS 会缩放函数范围,如果它在没有达到该名称的情况下进入全局范围,它会将 a 附加到global property该数据,而不是 a global variable.

但这确实给我们带来了关键——一个强大、稳定和可靠的 JS 应用程序,与其他应用程序一起生活在现代网页上,真的不应该太在意这些差异。
在这种情况下,目标是尽可能少地使用全局属性和变量。

此外,变量/财产碰撞的危险是相同的,无论它是什么。
变量对 是免疫的delete,但是任何有用的程序都将访问delete它从未设置过的属性的可能性有多大?

所以就个人而言,我认为理解边缘情况很好,但我也认为,虽然我内心的书呆子想同意存在差异,而且它们并不相连,但我内心的实用主义者会不寒而栗地想到一个人们正在积极使用全局范围,以至于这对他们产生了很大的影响。

于 2012-10-02T15:30:02.803 回答
2

一个很好的解释可以在这里找到,但我会缩短它来回答你的问题。当你说:

这两个术语代表完全相同的一组全局绑定。

...您几乎是正确的,但并不完全正确。像这样的属性分配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

})();

然而,这并不意味着全局属性和全局变量是相同的。所有属性都有三个隐藏标志:ReadOnlyDontEnumDontDelete

当使用隐式属性声明this.foo = 1时,DontDelete属性设置为false. 当您使用变量声明时var bar = 2,该DontDelete属性设置为true,因此在您使用运算符时表示它们之间的差异delete


针对您改写的问题:

[T]他的术语“全局变量”似乎是模棱两可的。有些人将其用作“全局属性”的同义词,而其他人将其定义为表示已通过 var 语句定义的全局属性。我的问题的目的是确定这两种含义中的哪一种是正确的。

该术语没有明确定义,因此您只是在征求意见。

通常,使用语法创建变量时使用术语“全局属性”,使用语法创建变量时使用this.foo = 1术语“全局变量” var bar = 2。没有什么可讨论的了。

这两个术语都与幕后发生的事情没有真正的关系,因此您能做的最好的事情就是了解幕后实际发生的事情,您已经完成了。

进一步要求两个任意术语的绝对定义只会使您成为一个不受欢迎的人。

于 2012-10-02T15:40:07.357 回答