命名函数优先于JavaScript中的匿名函数吗?

时间:2012-04-10 00:33:41

标签: javascript

  

可能重复:
  JavaScript: var functionName = function() {} vs function functionName() {}

在Javascript中提取函数有两种可能的方法:

var foo = function() { ... }

这有点做作;另一个常见的模式是:

var foo = {
   baz: 43,
   doSomething: function() {
       // ...
   }
}

function foo() { 
  // ... 
}

是否有明确的理由偏好其中一个?

4 个答案:

答案 0 :(得分:73)

这一切都取决于您声明功能的地方;吊装。

函数声明和变量声明总是被JavaScript解释器无形地移动到其包含范围的顶部("悬挂")。显然,功能参数和语言定义的名称已经存在。这意味着代码如下:

function foo() {
    bar();
    var x = 1;
}

实际上是这样解释的:

function foo() {
    var x;
    bar();
    x = 1;
}

请注意,声明的分配部分未被提升。只有名字被悬挂。函数声明不是这种情况,整个函数体也将被提升。

function test() {
    foo(); // TypeError "foo is not a function"
    bar(); // "this will run!"
    var foo = function () { // function expression assigned to local variable 'foo'
        alert("this won't run!");
    }
    function bar() { // function declaration, given the name 'bar'
        alert("this will run!");
    }
}
test();

在这种情况下,只有函数声明将其主体提升到顶部。名字' foo'被吊起,但尸体被遗忘,在执行期间被分配。

您可以为函数表达式中定义的函数指定名称,其语法类似于函数声明。这不会使它成为一个函数声明,并且名称不会被带入范围,也不会被提升。

foo(); // TypeError "foo is not a function"
bar(); // valid
baz(); // TypeError "baz is not a function"
bin(); // ReferenceError "bin is not defined"

var foo = function () {}; // anonymous function expression ('foo' gets hoisted)
function bar() {}; // function declaration ('bar' and the function body get hoisted)
var baz = function bin() {}; // named function expression (only 'baz' gets hoisted)

foo(); // valid
bar(); // valid
baz(); // valid
bin(); // ReferenceError "bin is not defined"

因此,如果您希望将功能提升到顶部,请使用function declaration,否则请使用expression。我更喜欢后者,因为我通常使用function expressions方法构建对象文字。

当抛出错误时,命名function expressions可以很方便。控制台将告诉您该功能是什么,而不是声明anonymous又名堆栈跟踪

答案 1 :(得分:10)

你在这里遇到了几件不同的事情,但我会先尝试解决你的主要问题。

一般......

function() { ... }函数表达式。语法上,这与2[4,5]处于同一级别。这表示。因此,var foo=function(){ ... }每次都会按计划运作。

function foo() { ... }是一个函数声明。这似乎和var foo=function(){...}的做法相同,但有一点需要注意。作为一个声明,它的工作方式类似于JS中的变量提升概念(基本上,所有变量声明都是在评估任何表达式之前完成的。)

一个很好的例子来自here

function test() {
    foo(); // TypeError "foo is not a function"
    bar(); // "this will run!"
    var foo = function () { // function expression assigned to local variable 'foo'
        alert("this won't run!");
    }
    function bar() { // function declaration, given the name 'bar'
        alert("this will run!");
    }
}
test();

基本上可变的提升使得价值达到顶峰,所以这段代码相当于(理论上 ):

function test() {
    var foo;//foo hoisted to top
    var bar=function(){//this as well
        alert("this will run!");
    }

    foo(); // TypeError "foo is not a function"
    bar(); // "this will run!"
    var foo = function () { // function expression assigned to local variable 'foo'
        alert("this won't run!");
    }
}

注意:我想利用这一点来说JS解释器很难遵循理论,所以不建议相信他们有些不确定的行为。 Here你会在理论和实践最终不起作用的部分末尾找到一个很好的例子(关于表达式与声明的主题还有更多细节)。

有趣的事实:在括号中包装function foo() {...}会将其从声明转换为表达式,这可能会导致一些奇怪的代码,如

(function foo() { return 1; })();// 1
foo; //ReferenceError: foo is not defined

如果您没有理由,请不要这样做。


摘要 var foo=function(){ ... } * sorta有点*与函数foo(){ ... }相同,不同之处在于前者执行您认为应该执行的操作,而后者确实很奇怪除非你将它包装在parens中,否则会影响范围,JS解释器允许你在规范中做一些被认为是语法错误的事情,这样你就会认为错误的事情实际上是正确的等等......

请使用函数表达式var f=function(){...})。没有真正的理由不这样做,特别是考虑到你在使用点语法时有点被迫这样做。


关于你触及的第二件事.....

我不确定该说些什么,它与其他一切完全不同。

var foo = {
    baz: 43,
    doSomething:function() {
        ...
    }
}

这称为对象文字语法。基于此语法的JSON是a pretty neat way of formatting data,JS中的这种语法通常用于声明新对象,例如使用单例对象(避免声明函数和使用new的所有混乱)。它也可以像使用XML一样使用,并且是所有酷孩子都喜欢的......

无论如何,基本上对象文字语法的工作原理如下:

{ name1: val1, .... namek:valk }

此表达式是在其上初始化某些值的对象。所以做var obj={ name1: val1, .... namek:valk }意味着:

obj.name1==val1;
obj['name1']==val1;// x['y'] is the same thing as x.y 
...
obj.namek==valk;

那么这与我们的例子有什么关系呢?基本上,您的表达式通常用于声明单例对象。但是它也可以用来声明一个对象原型,所以有人以后可以做var newObj = Object.create(foo),newObj会把foo作为原型。

如果你想真正了解它的实用性,请详细研究原型继承。道格拉斯·克罗克福德在他的许多会谈的one中详细谈到了这一点。

答案 2 :(得分:2)

命名函数没什么好处

  • 元分析的名称。 functionInstance.name会显示您的姓名。
  • 更重要的是,名称将以堆栈痕迹打印。
  • 名称也有助于编写自我记录或识字代码。

命名函数表达式

有一个缺点
  • IE有NFE的内存泄漏

除了较少的风格控制之外,函数声明没有缺点

答案 3 :(得分:1)

您的问题实际上由两部分组成,因为如果将函数分配给变量或属性,则不一定要使函数匿名。

命名与匿名?

@Raynos清楚地突出了要点。关于命名函数的最好的部分是它们将在堆栈跟踪中显示自己。即使在将函数分配给变量/属性的情况下,最好为函数命名以帮助调试,但我不会说匿名函数是邪恶的。它们确实有很好的用途:

Are anonymous functions a bad practice in JavaScript?

函数声明与函数表达式?

对于问题的这一部分,我会向您推荐这个问题,因为它可能比我更深入地涵盖了这个主题

var functionName = function() {} vs function functionName() {}