9

我似乎无法理解 JavaScript 变量范围的特定情况。与我发现的其他示例和问题不同,我对嵌套函数的范围感兴趣。

我在这个 JSFiddle上设置了一个例子。相关部分如下:

function MyObject() {
    var self = this;

    var a = 1;
    this.b = 2;

    var innerMethod = function() {
        //1 and 2: direct reference
        logMessage("a = " + a); // a = 1
        //logMessage("b = " + b); // Error: b is not defined

        //3 and 4: using this
        logMessage("this.a = " + this.a); // this.a = undefined
        logMessage("this.b = " + this.b); // this.b = undefined

        //5 and 6: using self
        logMessage("self.a = " + self.a); // self.a = undefined
        logMessage("self.b = " + self.b); // self.b = 2
    }
}

现在,我知道引用a直接有效。我也知道消息 3 和 4 ( this.aand this.b) 会失败,因为this它指的是内部函数。我也知道第 6 行有效,因为我保存了对原始对象的引用。

我不明白的是:

  • 为什么消息 1 和 2 不一样?
  • 为什么消息 5 和 6 的工作方式不同?
4

3 回答 3

4

a变量就是这样,一个变量。innerMethod它在(它只是一个嵌套函数)的范围内可见,因为a它是如何声明的(即 JavaScript 具有词法范围规则,内部函数可以看到它们在其中定义的函数的变量)。

thisMyObject构造函数的本地范围不同。

您已经看到 thatselfthisof的别名MyObject,并且已在其自己的范围内innerMethod被覆盖。this尽管如此,由于this不是函数范围的别名,因此self.athis.a不会在这里工作。

对于词汇范围的更严格解释,您可以例如从维基百科开始:http://en.wikipedia.org/wiki/Scope_(computer_science)

您可以在 ECMA 标准http://es5.github.com/#x10.3中阅读有关执行上下文和标识符解析规则的信息

于 2013-02-23T23:31:50.640 回答
1

这是范围的问题,当创建函数时,它们会保存周围的环境(包括变量)。

所以当innerMethod被创建时,它可以看到变量selfa.

一个重要的概念是作用域是在声明函数时创建的,而不是在调用函数时创建的。

在你的情况 1,b没有被声明(这个对象不一样)。

在案例 5 和 6 中,您没有创建self.a.

于 2013-02-23T23:29:43.183 回答
0

主要原因是self不等于在innerMethodthis的范围内。是引用函数所有者的关键字。对于innerMethod,它不是实例方法,它属于 Window。this

function MyObject() {
    var self = this;

    var innerMethod = function() {
        alert("inner method, self == this?: " + self == this); // false
        alert("inner method: " + this); // [object Window]
        alert("closest constructor name of in prototype chain ?: "+ this.__proto__.constructor.name); // Window
    }

    this.outerMethod = function(){
        innerMethod(); 
        alert("outer method: " + this); // [object MyObject]
        alert("closest constructor name in prototype chain?: "+ this.__proto__.constructor.name); // MyObject
    }
}

var o = new MyObject();
o.outerMethod();

你可以在这里玩

于 2015-02-05T11:51:35.343 回答