2

“[JavaScript 函数] 在内部存储它们可能引用的在其封闭范围中定义的任何变量。”

我怎样才能确定那组变量是什么?

例如,Effective JavaScript中的 David Herman给出了这个函数(和闭包):

function sandwichMaker() {

    var magicIngredient = "peanut butter";

    function make(filling) {
        return magicIngredient + " and " + filling;
    }

    return make;
}

var f = sandwichMaker();

document.writeln("<p>" + f("jelly") + "</p>");
document.writeln("<p>" + f("bananas") + "</p>");
document.writeln("<p>" + f("marshmallows") + "</p>");

当然,magicIngredient是 make() 可访问的变量,但还有什么?如果 SandwichMaker 本身包含在一个函数中会怎样?然后是全局变量。当函数在当前范围内查找相关值时,它在看什么?

4

3 回答 3

1

如果 SandwichMaker 本身包含在一个函数中会怎样?然后是全局变量。

是的,父函数中的所有变量都可以访问(如果它们没有被遮蔽)。然后,最高范围的函数从全局范围继承。

当函数在当前范围内查找相关值时,它在看什么?

您可以使用调试器进行检查。在 中插入一条debugger;语句make,然后执行它并查看您的开发工具。你会看到这样的东西:

Scope Chain
    0. make (currently executed):
        this: (+)Window
        arguments: (+)Arguments
        filling "jelly"
    1. sandwichMaker:
        arguments: (+)Arguments
        magicIngredient: "peanut butter"
        make: (+)Function
    Global
        AnonXMLHttpRequest: …
        ApplicationCache: …
        Array: …
        …

也看看这篇很棒的文章:http ://dmitrysoshnikov.com/ecmascript/es5-chapter-3-2-lexical-environments-ecmascript-implementation/

Chrome Devtools 的示例视图:

(来自www.briangrinstead.com

于 2013-01-16T19:07:42.910 回答
1

JavaScript 使用函数作用域。这很容易理解 - 在函数中声明的任何内容都具有该函数的范围以及任何更高的范围。

闭包可以被认为是两个组合在一起的东西:一个特定的范围和一个特定的时间点(当函数被创建时)。

当然,magicIngredient 是 make() 可访问的变量,但还有什么?

在创建时范围内可访问的任何内容make。这包括make函数中的所有变量以及任何更高的范围。据说 make 的作用域是封闭在它创建时存在的作用域之上,总是允许它访问magicIngredient.

如果 SandwichMaker 本身包含在一个函数中会怎样?

然后make也可以访问该范围(因为它在make创建时就存在)。

然后是全局变量。当函数在当前范围内查找相关值时,它在看什么?

解释器将在当前执行的范围内搜索任何引用的变量。如果找不到它们,它将在下一个更高的范围内查找。它将继续看起来越来越高,直到找到变量或用完范围(全局范围是最高的,也就是window在浏览器中运行的 javascript 的对象)。

一个相关的概念是阴影- 两个变量在父/子范围内可以具有相同的名称,子被称为“影子”父,因为它将优先。请注意,这是一种不好的做法。

理解闭包和作用域如何工作的最简单的方法是理解一个简单的工厂模式,比如这个。当内部函数被创建并返回时,它会在那个时间点绑定到那个范围,并且即使在值不再存在之后也会继续警告正确的值。

希望这会有所帮助-一个问题中塞满了很多问题:)

于 2013-01-16T19:19:53.683 回答
0

假设上面function sandwichMaker()定义了一个变量...

var something = 'something';
function sandwichMaker () {
...

您可以something从内部sandwichMaker()和从内部访问make()

外部变量可以从函数内部访问。如果您要设置var something = 'something else'inside make(),那么您将有效地将外部隐藏var somethingmake()函数本身内。但是,您可以只设置something = 'something else',并且该值将在所有范围内发生变化。如果您再次声明该变量,它只会隐藏该值。

于 2013-01-16T18:57:46.813 回答