如果全局上下文中的变量是属性,那么为了闭包的目的,如何区分它们

If variables in the global context are properties, then how are they distinguished for the purposes of closures?

本文关键字:闭包 何区 上下文 全局 变量 如果 属性      更新时间:2024-03-10

如果全局上下文中的变量是属性(在全局上下文上),那么为了闭包的目的,如何将它们与全局上下文上的其他属性区分开来?

显然这不起作用:

function foo() {
   this.a = 'a';
   this.bar = function() { console.log(a); }
}
new foo().bar(); // ReferenceError: a is not defined

显然,这确实有效:

var a = 'a';
function bar() {
  console.log(a);
}
bar(); // a

但如何给定变量a是一个"属性"。我的误解在哪里?

它们是不可区分的——它们只是一个变量和一个属性。您可以想象全局作用域是唯一可以作为实际语言对象访问的作用域对象。

全局环境由绑定到全局对象的环境记录(如with语句)组成,全局对象本身在浏览器中显示为window对象。

使用构造函数示例:

function Foo() {
   with (this) {
      this.a = 'a';
      this.bar = function() { console.log(a); }
      // Is `a` a variable or a property? It's *one* thing, available as both.
   }
}
new Foo().bar(); // 'a'

全局作用域是Web浏览器中的window对象。因此,全局范围中的变量声明成为window的属性。

// Somewhere in the global scope...
// Both declarations add a property to window
window.a = "hello world";
var a = "hello world";

另一方面,当使用this关键字将属性添加到对象时,并不是将其添加到内置的window对象中。这就是为什么闭包不会将this.a定位为a

如果您不使用this限定属性名称,则它是一个可以是局部或全局的变量-将全局理解为window对象的属性-。

JavaScript运行时在其当前范围内查找变量,否则在父范围内查找,依此类推,直到它到达全局范围,如果window不拥有属性(实际上是变量标识符),则浏览器或任何JavaScript运行时将确定该变量为未定义的。

在第一个示例中,this.a的作用域是foothis上下文。如果您将代码更改为:

function foo() {
   var a = 'a';
   this.bar = function() { console.log(a); }
}
new foo().bar();

它会起作用的。否则你必须这样做:

function foo() {
   this.a = 'a';
   this.bar = function() { console.log(this.a); }
}
new foo().bar();

第一个代码示例不起作用的原因是:

console.log(a);

正在bar()方法的范围中查找名为a的变量。但您从未声明过这样的变量。您只在名称为a的其他对象上声明了一个属性。如果你想引用该属性,你必须使用合适的对象引用,如下所示:

console.log(this.a);

Javascript中的所有属性都必须包括该属性所在的对象才能访问它们,全局对象上被视为全局变量的属性除外。因此,在您的上下文中,athis.a不是一回事。

只有在全局作用域中声明变量或显式附加到全局对象(在浏览器中为window),或者在没有声明的情况下隐式分配变量,并且您不处于严格模式下(我称这些意外的全局变量为可怕的事情),变量才是全局的。


所以,这里有几件事你可以做。

使用公共实例变量:

function foo() {
   this.a = 'a';
   this.bar = function() { console.log(this.a); }
}
new foo().bar(); // outputs the member variable a

或者使用构造函数局部变量(本质上是私有实例变量):

function foo() {
   var a = 'a';
   this.bar = function() { console.log(a); }
}
new foo().bar(); // outputs the member variable a

或者使用实际的全局(不推荐):

var a;
function foo() {
   a = 'a';
   this.bar = function() { console.log(a); }
}
new foo().bar();   // outputs the global a