10

我正在分析来自 John Resig 网站的以下两个 url,但我不明白给匿名函数命名是如何产生影响的。

我的理解是,给匿名函数的名称只能在函数定义内部使用,而不能在函数定义之外使用,但在以下链接中,它产生了巨大的不同

任何解释或参考都会有很大帮助。

我仍然对 #14 中的以下几行感到困惑

var samurai = { yell: ninja.yell }; 
var ninja = {};
assert( samurai.yell(4) == "hiyaaaa", "The method correctly calls itself." ); 

当 ninja 现在指向一个空白对象时,Samurai.yell 方法如何仍然能够指向 ninja.yell。

#13 和 #14 之间的唯一区别是为 #14 中的函数表达式提供名称。

ninja.yell 是否被复制到大喊而不被引用,或者这些 NAMED 函数表达式在某些场景中具有全局范围?

同样的事情发生在 #13 和 #14 中,唯一的区别是函数在 #14 中命名而在 #13 中未命名加上 ninja = {} 在 #14 中和 ninja = null 在 #13 中。是否有任何关于命名函数表达式的隐藏概念我错过了这使得 #14 可行而 #13 不可行。

4

4 回答 4

7

在内部示例中,您可以跳过 #13 中对 ninja 对象的额外访问

匿名闭包(ninja虽然我们已经在那个上下文中,但需要访问对象):

var ninja = { 
  yell: function(n){ 
    return n > 0 ? ninja.yell(n-1) + "a" : "hiy"; 
  } 
};

命名闭包可以直接调用:

var ninja = { 
  yell: function yell(n){ 
    return n > 0 ? yell(n-1) + "a" : "hiy"; 
  } 
};

另一个优点是命名闭包启用堆栈跟踪:

所以假设你这样做:

(function fooBar() { console.log(brazl); })();
// will create an error with "fooBar" in the stack trace instead of "anonymous function"

编辑:虽然它有时看起来像开销,但它有助于在开发过程中进行调试,例如 YUICompressor 和 Closure Compiler 可以在本质上不需要这些名称时去除它们

于 2012-04-25T15:43:20.287 回答
6

不想与 Kolink 好斗,但他说这不是一个好例子有点过分了。#14 与(在您共享的链接中)有关的是命名函数表达式(与函数声明不同的动物)。不管函数引用在哪里传递,如果你命名你的函数表达式,它总是有一种方法来调用它自己,从它自己内部。这个名字,你给你的函数表达式,是一个只有它知道的名字;它不存在于任何外部范围内。

有关函数表达式与函数声明的进一步讨论,请参见MDN 上的此处此处。底部的第二个链接有一个关于命名函数表达式的标题。它确实有用;有关一次性递归函数的示例,请参阅我的 Gist,它不会向本地或全局变量范围添加任何内容(例如,对于一次性 DOM 遍历很有用)。

此外,Tobias(在他的回答中)指出了命名函数表达式的其他良好用途,即在调试中。

于 2012-04-25T15:46:40.323 回答
2

在第一种情况下,该yell方法试图访问ninja.yell,而不管是哪个对象调用它。而在第二个中,它尝试调用yellwhich exists 因为该函数已命名。

这不是一个很好的例子。一个很好的例子是使用this.yell而不是ninja.yell,从而yell从当前对象中获取方法。

于 2012-04-25T15:39:19.243 回答
0

The site http://kangax.github.com/nfe/ is a great reference. Yes, as far as it is a function expression the name will only be available inside (e.g. for recursive calls, as in the demonstration) and also helps for debugging (e.g. in stack traces), because it sets the name property of the function.

于 2012-04-25T15:51:11.163 回答