如何在JavaScript中命名匿名函数有所不同?

时间:2012-04-25 15:33:46

标签: javascript

我正在分析John Resig网站上的以下两个网址,但我不明白为匿名功能命名是如何产生影响的。

我的理解是,匿名函数的名称只能在函数定义中使用,并且不在其中,但在以下链接中它会产生巨大的差异

任何解释或参考都将是一个很大的帮助。

我仍然对#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是否已经过COPIED而没有被引用,或者这些NAMED函数表达式在某些情况下具有全局范围?

同样的事情发生在#13和#14中,唯一的区别在于功能在#14中命名,在#13中未命名,加在#14中的ninja = {}和在#13中的ninja = null。是否存在任何关于命名功能表达的隐藏概念,这使得#14可行且#13无法工作。

4 个答案:

答案 0 :(得分:7)

在内部的示例中,您可以跳过#13

中对忍者对象的额外访问

匿名闭包(访问对象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可以剥离这些名称,如果它们基本上不需要

答案 1 :(得分:6)

不要试图与Kolink好斗,但他说这不是一个很好的例子。 #14与(在您共享的链接中)有关的是命名函数表达式(与函数声明不同的动物)。无论函数引用的传递位置如何,如果为函数表达式命名,它总是有一种从内部调用自身的方法。这个名称,你给你的函数表达式,是一个只有它知道的名称;它不存在于任何外部范围内。

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

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

答案 2 :(得分:2)

在第一种情况下,yell方法尝试访问ninja.yell,无论哪个对象调用它。而在第二种情况下,它会尝试调用yell,因为该函数已命名。

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

答案 3 :(得分:0)

网站http://kangax.github.com/nfe/是一个很好的参考。是的,只要它是一个函数表达式,名称将只在内部可用(例如,对于递归调用,如演示中),并且还有助于调试(例如在堆栈跟踪中),因为它设置了name属性功能。