关于语法:在javascript中声明函数

Declaring functions in JavaScript

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Javascript: var functionName = function() {} vs function functionName() {}

这两种声明函数的方法有什么区别?

1
2
3
function someFunc() { ... }

var someFunc = function() { ... }

我不是在问技术问题。我不是在问哪一种更易于阅读,或者哪种风格更受欢迎。


我和这里的大多数人意见不同。从技术上讲,这种语法对于以两种方式声明函数来说可能是相同的。(我的最后一句话不正确。我在一篇不同的文章中读到了为什么它们在技术上是不同的,最后我会补充一句,为什么)但是它们在进化模式中扮演角色的方式是巨大的。我强烈推荐Doughlas Crockford的"javascript:好的部分"。

但为了以一种微妙而简单的方式证明我的观点,这里有一个小例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//Global function existing to serve everyone
function swearOutLoud(swearWord) {
    alert("You"+ swearWord);          
}
//global functions' territory ends here

//here is mr. spongebob. He is very passionate about his objects; but he's a bit rude.
var spongeBob = {
    name :"squarePants",
    swear : function(swearWord) {
                name ="spongy";
                alert("You"+ swearWord);
                return this;
            }
}

//finally spongebob learns good manners too. EVOLUTION!
spongeBob.apologize = function() {
    alert("Hey" + this.name +", I'm sorry man!");
    return this;
}


//Ask spongebob to swear and then apologize in one go (CASCADING EFFECT!!)
alert(spongeBob.swear("twit").apologize());

如果你看上面的代码,我声明了一个名为swearoutlod的函数。它将从任何对象或调用中提取一个脏话,并将为您提供输出。它可以使用传递给它的"this"参数和参数对任何对象执行操作。

但是,第二个声明声明声明为名为"spongebob"的对象的属性。需要注意的是,这一点很重要,因为我正朝着一种对象驱动的行为前进。当我返回"this"时,我还保持"级联效应",如果我没有其他东西可以返回。

类似的事情在jquery中完成;如果您试图编写框架或其他东西,这种级联模式很重要。您还将把它链接到构建器设计模式。

但是,通过将函数声明为对象的属性,我能够实现以对象为中心的行为,从而获得更好的编程范式。除非设计得很好,否则使用全局访问在外部声明的单个函数将导致非面向对象的编码方式。不知怎么的,我更喜欢后者。

要查看级联的效果,请查看最后一个语句,在该语句中可以要求海绵宝宝立即宣誓和道歉;即使稍后将道歉添加为属性。

我希望我能澄清我的观点。从技术的角度来看,差异可能很小;但是从设计和代码进化的角度来看,差异很大,会造成一个不同的世界。

但那只是我!拿着还是放着。:)

编辑:

所以这两个调用在技术上是不同的;因为命名声明绑定到全局命名空间,并在解析时定义。所以可以在声明函数之前调用。

1
2
3
4
5
6
 //success
 swearOutLoud("Damn");

function swearOutLoud(swearWord) {
    alert("You" + swearWord)
}

以上代码将正常工作。但下面的代码不会。

1
2
3
4
swear("Damn!");
    var swear = function(swearWord) {
    console.log(swearWord);
}


使用function someFunc() { ... }的一个优点是函数名出现在Firebug调试器中。以另一种方式声明的函数(var someFunc = function() { ... })以匿名方式出现。


在样式方面,第二个示例与声明函数的其他常见方法更为一致,因此可以认为它更具可读性。

1
2
3
this.someFunc = function() { ... }
...
someFunc: function() { ... },

但是,正如前面提到的,它是匿名的,因此在分析时不会显示名称。声明函数的另一种方法是如下所示,它使您在两个世界中都得到了最好的结果

1
var someFunc = function someFunc() { ... }

实际上,不同之处在于,第二个声明使我们能够声明这样的函数,从而可以将函数作为对象的属性:

1
2
var myObject=new Object();
myObject.someFunc=function() { ... };

第一种形式是:

1
function test() { }

是一种公认的语法,第二种形式是:

1
var test = function() { ... }

允许您控制函数的范围(通过使用var;如果没有var,它将是全局的)。

你甚至可以同时做到:

1
var test = function test() { ... test(); ... }

这允许您以第二种形式定义递归函数。


另一个区别是,在大多数浏览器上,后者允许您根据情况定义不同的实现,而前者则不允许。假设您需要跨浏览器事件订阅。如果您试图定义一个addEventListenerTo函数,那么:

1
2
3
4
5
6
7
8
9
10
11
12
13
if (document.addEventListener) {
    function addEventListenerTo(target, event, listener) {
        ....
    }
} else if (document.attachEvent) {
    function addEventListenerTo(target, event, listener) {
        ....
    }
} else {
    function addEventListenerTo(target, event, listener) {
        ....
    }
}

在某些浏览器中,所有函数最终都会被解析,最后一个函数优先。结果:上述方法不起作用。但是,将匿名函数分配给变量是可行的。您还可以使用分配给变量的匿名函数应用功能性和基本面向方面的编程技术。

1
2
3
4
5
6
7
8
9
10
11
var fib = memoize(function (n) {
    if (n < 0) return 0;
    if (n < 2) return 1;
    return fib(n-1) + fib(n-2);
});

...
// patch the $ library function
if (...) {
    $ = around($, fixArg, fixResult);
}


对于可读性,我认为第一个明显更好。未来的维护程序员,即使他们对javascript足够熟悉,知道这个线程中出现的许多更好的点,也将采用第一种格式。

例如,如果有一天他们希望ctrl-f搜索函数的定义以查看其中发生了什么,他们是要首先搜索someFunc = function()还是function someFunc()

此外,为了准确地排版(因为我们讨论的是可读性),读者通常会快速扫描文本,如果他们在寻找函数定义,他们更倾向于跳过以"var"开头的行。

我知道这是一个非技术性的答案,但人类比计算机更难阅读代码。


当你写作时

1
2
function Test() {
}

Javascript实际上正在创建一个属性,它将向该属性分配函数对象,一旦调用该对象,将执行函数定义中报告的代码。属性附加到对象window或包含函数定义的对象。