2012-09-06 26 views
2

在另一个线程我开始了评论,有人这样说:命名一个函数(而不是离开它)和创建对它的引用有什么区别?

@adlwalrus肯定。试试这个:var foo = function bar(){};的console.log(FOO);但请注意,酒吧只是功能名称(这是什么意思,我不确定我是否确切地自己)而不是对它的引用,所以不能通过执行bar()来调用它。分配(甚至命名的函数)与声明函数不同。提升(碰到范围顶部)只适用于声明,分配将保持原样。 - valentinas 6小时前

如果不能用bar()调用它,函数名会起什么作用?

+1

你的名字和你的地址有什么区别? –

+0

除了名称/地址类比之外,实际上可以在bar()的作用域内调用bar(),但在bar()的作用域外,必须使用foo()。 – jeremy

+0

@HotLicks - 这种比喻毫无意义。 'foo'和'bar'在这里都是清晰的名字。他们都提到相同的*地址*。这只是在新功能的范围内才可用。 –

回答

3

有两种方法可以在JavaScript中创建函数,即“函数声明”和“函数表达式”。我相信这是Doug Crockford最好的解释,他指出,除非“函数”是给定行上的第一组字符,否则您正在执行函数表达式(不是声明)。

功能声明是挑剔的生物。当你看到它们时你会认出它们。他们是这样的:

function foo() { /* ... */ } 

他们总是一个名字(它的报应)和名字被局部范围在其下函数声明为词法环境。所以如果你在全局上下文中执行一个函数声明,那么这个函数可以通过它的全局名称被引用。如果你在一个函数中执行它,那么该函数的名字只能在该函数中被引用,并且在该函数中声明的任何函数都可以被引用。

我认为这种声明函数的方法中最重要的方面就是函数初始化会被提升到当前词法上下文的顶部。因此,你应该永远,永远使用函数声明中的条件,比如这个:

//DON'T DO THIS! 
if (x) { 
    function foo() { return 1; } 
} else { 
    function foo() { return 2; } 
} 

foo(); //will always be 2, regardless of the value of x. 

函数表达式略有不同。通常情况下,他们直接分配给一个变量,像这样:

var foo = function() { /* ... */ }; 

这是几乎相同的函数声明,除了上述初始化不悬挂。所以你可以做到以下几点:

var foo; 
if (x) { 
    foo = function() { return 1; }; 
} else { 
    foo = function() { return 2; }; 
} 

foo(); //will be 1 or 2, depending on the truthy-ness of x. 

那么,回到原来的问题。函数表达式也可以有一个名称,尽管它不是必需的,并且它没有作用于声明函数的上下文(与函数声明一样)。相反,它将范围限定在函数自己的词汇上下文中。这在某些情况下非常有用。我个人最喜欢的是这个模式:

(function foo() { 
    //Do something. 

    setTimeout(foo, 1000); 
}()); 

foo; //undefined 

因为单词“功能”前的括号,这是一个函数表达式和名称仅供内部作用域。但没关系,因为我们只需要在内部调用它(通过setTimeout())。结果是该函数将立即执行一次,然后在执行完成后每秒钟左右重新执行一次。这比使用setInterval()更安全,因为它会在重新计划自身之前一直等待执行完毕,从而防止可能导致错误执行和/或“支配”JavaScript线程的重叠。

从本质上讲,命名函数表达式的使用是有限的,但是当你需要它时,它是非常强大的。

+0

这是一个令人难以置信的信息答案。它被接受了,我认为有一种“礼物”声望的方式,如果有的话我会这样做,但我找不到它。我希望你能成为我的JS老师。如果你写了一本教科书,我会买它。你有博客吗? – wwaawaw

+0

@adlwalrus我很欣赏赞美。我没有博客或书籍或类似的东西。但我建议您查看Doug Crockford的JavaScript讲座(搜索“Crockford on JavaScript”)。它们非常棒,是我对JavaScript所了解最多的源代码。 :-) – Pete

+0

你读过/你会推荐/ The Good Parts /?我的一个朋友拥有它,所以我可以借用它,如果我想。 – wwaawaw

4

用于调用自身的函数。

var x = function y(val){ 
      if (val){ 
       console.log(val); 
       y(val-1); 
      } 
     }; 
x(5); 
> 3 
> 2 
> 1 
y(3); 
> ReferenceError: y is not defined 
+0

好吧,那么他们就不会与其他任何东西发生冲突,真的。 IE,你可以有: 'var x = function z(v){if(v){console.log(v); z(v-1);}}; var y = function z(v){if(v){console.log(v); z(v-1);}};' – wwaawaw

+0

注意两个内部都标记为'z'的函数。 – wwaawaw

+0

@adlwalrus是的,这是正确的见http://jsfiddle.net/mowglisanu/gAHXg/ – Musa

4

你指的是一个名为函数表达式。规范要求这些函数的名称仅在新函数的范围内可用。 Spec quote

在FunctionExpression标识符可以从内部 的FunctionExpression的函数体中引用允许函数递归调用 本身。但是,与FunctionDeclaration不同,FunctionExpression中的 标识符不能被引用,并且 也不会影响包含FunctionExpression的范围。

在另一方面,结果表达的是新的功能,它可以被保存和参考的任何位置的参考。

很多细节在这里:

我读了整个事情。

至于好处,另一个是它使它们更易于在调试器中识别。

+0

非常有趣,也很复杂。 – wwaawaw

相关问题