6

我正在尝试了解 JavaScript 范围规则。我在教科书和文档中读到的内容令人困惑。

在我看来,JavaScript 是一种静态(或词法)范围的语言 - 当试图将变量名绑定到变量(定义)时,会使用代码的词法结构。

执行上下文似乎类似于调用堆栈上的堆栈帧。每个执行上下文都有一个变量对象,所有局部变量(相关函数的)都在该变量对象上定义。这些变量对象链接在一起以提供从堆栈顶部的变量对象到堆栈底部的变量对象(窗口对象)的“范围链”。在将变量名称绑定到变量时,从上到下搜索此范围链。这与 C/C++/Java 等静态范围语言非常相似。

与 C/C++/Java 相比,似乎有一个重要的区别——可以访问在堆栈帧不再位于调用堆栈上的函数中定义的变量,如下例所示:

var color = "red";
var printColor;

function changeColor() {
    var color = "green";

    printColor = function(msg) {
        alert(msg + color);
    }
    printColor("in changeColor context, color = ");  // "green"
}

changeColor();

// stack frame for "changeColor" no longer on stack
// but we can access the value of the variable color defined in that function

printColor("in global context, color = ");  // "green"

我做对了吗?还有其他我应该注意的问题吗?

提前致谢

4

2 回答 2

3

这确实是 C/C++ 和 JavaScript 之间的一个主要区别:JavaScript 是一种引用计数、垃圾收集的语言,这意味着当对象不再有任何对它们的引用时,它们可以被引擎回收。您分配给的函数printColor本身并不在堆栈上,就像在 C 或 C++ 中那样;它是动态分配的,然后分配给当前范围之外的变量。因此,当控制流从 中返回时 changeColor,匿名函数的引用计数仍然为1 ,因为外部printColor引用了它,因此它可以在外部范围内使用。

因此,您的示例并不是一个范围界定问题——很明显, 您printColor changeColor. 当您定义 changeColor时,它 会将 upvalue 关闭printColor到新函数范围内,使其可访问。就像 Combat所说的那样,如果您将 a 添加var到 的第二个内部定义中 printColor,它将遮盖 声明的第一个 定义,printColor并且在该功能块之外无法访问它。

至于其他需要注意的问题,是的,有很多,但是请参阅我对您原始帖子的评论以获得良好的开端。

于 2012-06-21T23:54:14.277 回答
1

它总是归结为词法作用域,即函数在定义时使用其作用域链执行,而不是在调用时。

匿名函数是在函数 changeColor 的局部范围内定义的,而不是在全局范围内。因此,当它再次执行时,它会打印出列在函数 changeColor 的本地范围内的绿色。

于 2014-11-18T09:01:49.203 回答