【问题标题】:JavaScript local scoping: var vs. thisJavaScript 本地作用域:var 与 this
【发布时间】:2013-02-23 23:23:21
【问题描述】:

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

我在this 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.athis.b)会失败,因为 this 指的是内部函数。我也知道第 6 行有效,因为我保存了对原始对象的引用。

我不明白的是:

  • 为什么消息 1 和 2 不一样?
  • 为什么消息 5 和 6 不一样?

【问题讨论】:

  • 为什么它们的工作方式一样?似乎您是在用 Java 或其他某种语言进行类比,其中 this 命名空间是隐式的,而 JS 并非如此。
  • @FabrícioMatté 我这样做可能是无意识的(双关语)。我不明白范围界定是否应该使变量/成员自动暴露给内部成员。好像不是这样,因为不一致。
  • @Alpha 您将变量 (var a = 5;) 与不是变量而是对象属性的事物进行比较(this.b = 10; 设置 this 所指对象的属性 b 10)。这些东西不一样,因此行为也不相同。
  • 我在想一个简单的方法来解释它,但基本上 JS 的词法范围不会像你说的那样自动将成员暴露给内部成员。
  • @Alpha 看看如果你做了innerMethod.call(this);this.method = innerMethod;(new MyObject()).method();,4 会发生什么变化

标签: javascript scope scoping


【解决方案1】:

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

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

您已经看到selfMyObjectthis 的别名,并且innerMethod 在其自己的范围内覆盖了this。尽管如此,由于this 不是函数作用域的别名,所以self.athis.a 都不会在这里工作。

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

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

【讨论】:

  • 我更喜欢在第三段中使用VariableEnvironment 而不是function scope,并说明第一段背后的原因是JS 有lexical scope。但解释得很好。
  • 我已经合并了您的一些更改,但我很犹豫将 VariableEnvironment 交换为函数范围。尽管它在技术上更正确,但我相信函数范围是一个为来自其他语言的程序员所熟知的概念。我已将您的链接添加到 ECMA 标准。
【解决方案2】:

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

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

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

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

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

【讨论】:

    【解决方案3】:

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

    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();
    

    你可以在here

    【讨论】:

      猜你喜欢
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-18
      • 1970-01-01
      • 2013-01-12
      • 2010-12-29
      • 1970-01-01
      相关资源
      最近更新 更多