为什么命名的javascript函数会持续存在?

时间:2014-12-10 11:23:47

标签: javascript function closures function-expression

这是对你在john resig的Learning Advanced Javascript app中找到的内容的改编。

var math = {
    fact: function fact(n){
        return n > 0 ? n * fact(n-1): 1;
    },
    fact1: function (n) {
        return n > 0? n * math.fact1(n-1) : 1;
    }
};

console.log(math.fact(5));  // 120
console.log(math.fact1(5)); // 120

var o = {
    x: math.fact,
    y: math.fact1
};

math = {};

console.log(o.x === undefined); // false
console.log(o.y === undefined); // false
console.log(o.x(5));            // 120
console.log(o.y(5));            // Uncaught TypeError: math.fact1 is not a function

人们会期望o.x(5)应该抛出一个错误,但它会执行。为什么呢?

3 个答案:

答案 0 :(得分:5)

评估对象文字表达式时,将评估每个冒号右侧的表达式并将其分配给指定的属性。

所以当执行时:

var o = {
    x: math.fact,
    y: math.fact1
};

评估表达式math.fact,结果是math.fact当时指的是的函数

math.fact1同样如此。

因此,即使您使用math重新分配math = {}变量。 o.x将继续参考该功能。 o对象不了解math变量。

<小时/> o.y(5)抛出错误的原因与闭包有关。

o.y指的是这个函数:

function (n) {
     return n > 0? n * math.fact1(n-1) : 1;
}

您可以在此处看到它使用math 变量。即使您重新分配math变量,此函数也将继续引用变量本身。

当您调用o.y(5)时,该函数会执行,但当它尝试调用math.fact(n-1)时,会失败,因为math不再具有名为fact的属性。< / p>

<小时/> o.x没有o.y的问题。它是一个命名函数,因此即使在重新分配math之后也可以继续调用它。

答案 1 :(得分:3)

我不明白为什么你会在o.x上发现错误。

一开始,当我们定义math = { ... }时,我们有两个函数。

第一个函数的名称为fact,以及对象属性math.fact

第二个函数是匿名函数,仅由math.fact1

引用

然后我们将这些功能“复制”到o。此时,第一个函数由factmath.facto.x引用,而第二个函数由math.fact1o.y引用。< / p>

然后我们通过用一个新的空对象替换它来销毁math对象。此时,第一个函数由facto.x引用,第二个函数仅由o.y引用。

现在我们实际上调用了这些函数。 o.x包含对fact的递归调用,该调用非常明确地定义为该函数。但是,o.y包含对math.fact1的递归调用,我们将其销毁,因此出现错误。

这与任何感兴趣的东西无关。命名仍然存在的东西的函数继续工作,而命名不存在的东西的函数失败。

我的意思是......呃...

答案 2 :(得分:1)

o.x是对函数(对象)的引用。由于这个引用,在重置数学对象之后,事实函数将保持存在(对象只在不再存在对它们的引用时才会收集垃圾)。