【问题标题】:why does the named javascript function persist?为什么命名的javascript函数仍然存在?
【发布时间】:2014-12-10 11:23:46
【问题描述】:

这是对您在 john resig 的 Learning Advanced Javascript 应用程序中找到的内容的改编。

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) 应该抛出一个错误,但它会执行。为什么?

【问题讨论】:

  • 我不明白你为什么会期待一个错误......
  • o.y(5) 抛出错误......所以不应该o.x(5)

标签: javascript function closures function-expression


【解决方案1】:

当一个对象字面量表达式被计算时,每个冒号右边的表达式被计算并分配给指定的属性。

所以当它执行时:

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 的属性。


o.x 没有o.y 的问题。它是一个命名函数,因此即使在重新分配math 之后也能够继续调用自身。

【讨论】:

  • 这更有意义......当我用 arguments.callee 替换 math.fact1 时,它起作用了。现在一切都说得通了……我从来没有想过这是错误的原因。
  • 我认为arguments.callee 现在已被弃用,因此请注意这一点。
  • @deostroll 我很高兴我能够解决这个问题。请记住,不建议使用arguments.callee,并且在ES5严格模式下禁止使用。像在fact() 中那样使用命名函数是首选方法。
【解决方案2】:

我不明白您为什么会在 o.x 上看到错误。

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

第一个函数由其名称fact 和对象属性math.fact 引用两者

第二个函数是匿名的,只被math.fact1引用

然后我们将函数“复制”到o。此时,第一个函数被factmath.facto.x全部引用,而第二个函数被math.fact1o.y引用。

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

现在我们实际调用函数。 o.x 包含对fact 的递归调用,它仍然非常清楚地定义为该函数。但是,o.y 包含对 math.fact1 的递归调用,我们将其销毁,因此出现错误。

这与......好吧,任何有趣的事情无关。命名仍然存在的东西的函数继续工作,而命名不再存在的东西的函数失败。

我的意思是……呃……

【讨论】:

  • 这个答案更具描述性,并且解释得很好
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 2011-08-03
    • 1970-01-01
    • 2015-02-10
    • 1970-01-01
    • 2014-10-09
    • 2019-01-11
    • 1970-01-01
    • 2015-09-30
    • 1970-01-01
    相关资源
    最近更新 更多