在JavaScript中命名匿名函数有什么不同?

在JavaScript中命名匿名函数有什么不同?,javascript,Javascript,我正在分析John Resig网站上的以下两个URL,但我不明白给匿名函数起名字有什么不同 我的理解是,匿名函数的名称只能在函数定义内部使用,而不能在函数定义外部使用,但在以下链接中,它起着巨大的作用 任何解释或参考都会大有帮助 我仍然对#14中的以下几行感到困惑 当忍者指向一个空白物体时,武士吼叫法怎么还能指向忍者吼叫呢 #13和#14之间的唯一区别是为#14中的函数表达式提供名称 ninja.yell是否被复制到yell而未被引用,或者此类命名函数表达式在某些场景中具有全局作用域?

我正在分析John Resig网站上的以下两个URL,但我不明白给匿名函数起名字有什么不同

我的理解是,匿名函数的名称只能在函数定义内部使用,而不能在函数定义外部使用,但在以下链接中,它起着巨大的作用

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

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

当忍者指向一个空白物体时,武士吼叫法怎么还能指向忍者吼叫呢

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

ninja.yell是否被复制到yell而未被引用,或者此类命名函数表达式在某些场景中具有全局作用域?


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

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


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

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

匿名关闭(需要访问对象
ninja
,尽管我们已经处于该上下文中):

可以直接调用命名闭包:

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编译器可以去掉这些名称(如果它们根本不需要的话)

不试图与Kolink进行斗争,但他说这不是一个好的示例,这有点过头了。#14与命名函数表达式(与函数声明不同)有关(在您共享的链接中)。不管函数引用在何处传递,如果命名函数表达式,它总是有一种从自身内部调用自身的方法。这个名字,你给你的函数表达式,是一个只有它知道的名字;它不存在于任何外部作用域中

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


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

该网站是一个很好的参考。是的,就函数表达式而言,名称仅在内部可用(例如,对于递归调用,如在演示中),也有助于调试(例如,在堆栈跟踪中),因为它设置函数的
name
属性。

不仅仅是函数的名称;它是一个命名函数表达式,而不仅仅是一个函数声明(必须有名称)。区别不仅仅是语义上的。函数有一种始终引用自身的方法,因为范围可以通过
调用
应用
注入,而对函数的原始引用被删除,使得命名函数表达式非常有用,IMHO.谢谢你让答案更精确,但我仍然对#14-武士.叫喊法如何仍然能够指向忍者.当忍者指向一个空白对象时叫喊.好的,它是如何工作的:当对象通过对象文字组成时,匿名函数被分配给
ninja.yell
。然后将
ninja.yell
中的函数对象(因为所有JS函数都是一级对象)分配给
samurai.yell
<代码>忍者然后被擦干净:它被分配了一个空白的新对象。但是
samurai.yell
仍然持有对原始函数对象的引用,因此它不是垃圾收集的;它还活着。只要有一个对任何对象的引用仍然存在,就不会发生垃圾收集,并且对象仍然存在。有意义吗?感谢Paul带来了垃圾收集点,我在#14中没有理解,但同样的事情在#13中也发生了,但它不起作用。唯一的区别是表达式在#14中命名,在#13中未命名,加上#13中的ninja=null和#14中的ninja={}。关于命名函数表达式,还有什么隐藏的概念是我遗漏的,它使#14可行但不可行?好的,我会更彻底地阅读你的观点,并再次分析#13和#14。我想说的是,13和14之间还有一个区别,我们把叫喊叫做忍者。现在我明白了,我认为你的回答是正确的。非常感谢保罗:)回答得好,保罗。但是,即使不命名函数,它仍然可以通过
参数调用自己。被调用方
,如Resig的下一个示例(#15)所示。即使将
ninja
设置为null,如果通过
参数进行递归,则通过
samurai
现在引用的匿名函数进行的递归也可以完美地工作。我的观察和结论是正确的,还是我遗漏了什么?谢谢
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"