确定JavaScript闭包中可访问的变量集

时间:2013-01-16 18:50:07

标签: javascript scope closures

" [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本身在一个函数内怎么办?然后是全局变量。在当前范围内查找相关值时查看的函数是什么?

3 个答案:

答案 0 :(得分:1)

  

如果sandwichMaker本身属于一个函数,该怎么办?然后是全局变量。

是的,来自父函数的所有变量都是可访问的(如果它们没有被遮蔽)。而最高范围的函数则继承自全局范围。

  

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

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

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的示例视图:

http://briangrinstead.com/files/scope-variables.png

(来自www.briangrinstead.com

答案 1 :(得分:1)

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

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

  

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

创建时make范围内可访问的任何内容。这包括make函数中的所有变量以及任何更高的范围。 make的范围被称为封闭在创建时存在的范围,始终允许其访问magicIngredient

  

如果sandwichMaker本身属于一个函数,该怎么办?

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

  

然后有全局变量。它看起来的功能是什么?   对于当前范围内的相关值?

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

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

了解闭包和作用域的最简单方法是了解简单的工厂模式,例如this one。创建并返回内部函数时,它会在该时间点绑定到该作用域,并且即使在值不再存在之后也会继续警告正确的值。

希望这有所帮助 - 很多问题都塞进了一个问题:)

答案 2 :(得分:0)

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

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

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

可以从函数中访问外部变量。如果您要在var something = 'something else'内设置make(),那么您将在var something函数本身内隐藏外部make()。但是,您只需设置something = 'something else',该值就会在所有范围内更改。如果再次声明该变量,它只会隐藏该值。