我正在分析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无法工作。
答案 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上的here和here。底部的第二个链接有一个关于命名函数表达式的标题。 确实有用;有关一次性递归函数的示例,请参阅my Gist,它不会向本地或全局变量范围添加任何内容(例如,对于一次性DOM遍历非常有用)。
此外,Tobias(在他的回答中)指出了命名函数表达式的其他好用法,即在调试中。
答案 2 :(得分:2)
在第一种情况下,yell
方法尝试访问ninja.yell
,无论哪个对象调用它。而在第二种情况下,它会尝试调用yell
,因为该函数已命名。
这不是一个好例子。一个很好的示例是使用this.yell
而不是ninja.yell
,从而从当前对象获取yell
方法。
答案 3 :(得分:0)
网站http://kangax.github.com/nfe/是一个很好的参考。是的,只要它是一个函数表达式,名称将只在内部可用(例如,对于递归调用,如演示中),并且还有助于调试(例如在堆栈跟踪中),因为它设置了name
属性功能。