3

假设我们在containerFunction其中定义了两个函数:

var innerFunction1link;
var innerFunction2link;

function containerFunction() {
    var someInnerVariable = 1;

    innerFunction1link = innerFunction1;
    innerFunction2link = innerFunction2;

    function innerFunction1() {
        console.log("I'm 1 " + someOuterVariable + " " + (someInnerVariable++));
    }

    function innerFunction2() {
        console.log("I'm 2 " + someOuterVariable + " " + (someInnerVariable++));
    }
}


containerFunction();
var someOuterVariable = 42;

// Point A
innerFunction1link();
innerFunction2link();

someOuterVariable = "WAT?!";

// Point B
innerFunction1link();
innerFunction2link();

现在的问题。根据“JavaScript Ninja 的秘密”一书,每个闭包都有自己的私有变量集(包括后面定义的变量,如someOuterVariable):

私人泡泡

因此innerFunction1,并且在asinnerFunction2之外引用,并且将有它们的“私人泡沫”,其中包含全套变量。在“A 点”,两个函数都可以正常执行并输出:containerFunctioninnerFunction1linkinnerFunction2link

I'm 1 42 1
I'm 2 42 2

然后,当我设置someOuterVariable为时"WAT?!",输出为:

I'm 1 WAT?! 3
I'm 2 WAT?! 4

两个“私人泡沫”的价值someOuterVariablesomeInnerValue实际更新将如何(如果有 1000 个这些泡沫会怎样)?它实际上是否跟踪对所有变量的所有引用?如果一个闭包更新,它的值将如何填充到另一个闭包?someOuterVariable

更新

即使innerFunction's 将在不同的上下文中定义,它们仍然会“共享”变量:

function containerFunction1() {
    var someInnerVariable = 1;

    innerFunction1link = innerFunction1;

    function innerFunction1() {
        console.log("I'm 1 " + someOuterVariable + " " + (someInnerVariable++));
    }
}

function containerFunction2() {
    var someInnerVariable = 1;

    innerFunction2link = innerFunction2;
    function innerFunction2() {
        console.log("I'm 2 " + someOuterVariable + " " + (someInnerVariable++));
    }
}

containerFunction1();
containerFunction2();
var someOuterVariable = 42;

innerFunction1link();
innerFunction2link();

someOuterVariable = "WAT?!";

innerFunction1link();
innerFunction2link();

输出:

I'm 1 42 1 
I'm 2 42 1
I'm 1 WAT?! 2
I'm 2 WAT?! 2 
4

2 回答 2

6

比使用私有气泡更好的描述是每个函数都保留对定义它的范围的引用。

必须明确它是参考而不是副本

这解释了两个 innerFunctions 指向相同的范围,因此指向相同的变量集。这些变量也可以在外部范围内或通过任何指向此范围的函数进行更改。

作为补充说明:每次调用函数时都会在 JavaScript 中创建一个作用域(还有其他作用域,最值得注意的是全局作用域,还有可以使用with或创建的作用域try/catch)。

于 2013-07-02T15:37:25.700 回答
1

因此innerFunction1,并且在asinnerFunction2之外引用,并且将有它们的“私人泡沫”,其中包含全套变量。containerFunctioninnerFunction1linkinnerFunction2link

并不真地。它们的气泡非常空,但从它们内部你可以透过气泡的墙壁看到更大的气泡containerFunction。在那里,您可以看到 4 个变量:containerFunctionsomeInnerVariable和。从那个气泡中,您可以看到带有、、和变量的全局气泡。innerFunction1innerFunction2innerFunction1linkinnerFunction2linksomeVariablecontainerFunctionsomeOuterVariable

因此,与其在气泡中复制大量的每个变量,它们只是指向更高气泡中的共享变量的指针。如果它们是从任何地方更新的,您也可以从您的私人泡泡中看到。

现在用“范围”替换每次出现的“泡沫”一词:-)

于 2013-07-02T15:44:23.007 回答