js中有两种声明函数的方法,分别为:
var functionOne = function() { // Some code }; function functionTwo() { // Some code }
为什么会有两种不同的方法?每个方法的优点和缺点分别是什么?有什么情况是一种方法能完成而另外一种方法不能完成的吗?
答: |
by @Greg
不同点在于functionOne只会在到达赋值的那一行才会被真正定义,而functionTwo会在 包含它的函数或script脚本 执行的时候马上被定义。例如:
1 <script> 2 // Error undefined 3 functionOne(); 4 5 var functionOne = function() { 6 }; 7 8 // No error 9 functionOne(); 10 </script> 11 12 <script> 13 // No error 14 functionTwo(); 15 16 function functionTwo() { 17 } 18 </script>
这也意味着你不能在条件语句中使用第二种方法定义函数:
<script> if (test) { // Error or misbehavior function functionThree() { doSomething(); } } </script>
上面的例子无论test的值是真是假,实际上已经定义了functionThree函数。
by @Eugene Lazutkin
另外,也可以结合以上两种函数定义方法:
var xyz = function abc(){};
xyz 函数将会正常定义。而 abc 函数不会在浏览器中定义(除了IE浏览器),但是在其函数体内可见:
var xyz = function abc(){ // xyz is visible here // abc is visible here } // xyz is visible here // abc is undefined here
如果你想在所有浏览器中使用函数别名,可以使用这种声明方式:
function abc(){}; var xyz = abc;
这种情况下 xyz 和 abc 是同一个函数对象的别名:
console.log(xyz === abc); // prints "true"
使用第二种方式进行函数定义的一个说服性理由是,该函数对象有"name"属性(IE不支持)。当你定义一个类似下面的函数:
function abc(){}; console.log(abc.name); // prints "abc"
函数的name属性会被自动分配。但是当你以下面的方式定义函数:
var abc = function(){}; console.log(abc.name); // prints ""
它的name属性为空——这里创建了一个匿名函数,并将它赋值给其他变量。
推荐使用第二种函数定义方法的另一个理由是,可以用一个简短的内部名称来引用函数本身,同时为外部用户提供一个长的无冲突的别名:
// Assume really.long.external.scoped is {} really.long.external.scoped.name = function shortcut(n){ // Let it call itself recursively: 循环调用其本身 shortcut(n - 1); // ... // Let is pass itself as a callback: 作为回调函数来传参 someFunction(shortcut); // ... }
在上面的例子中我们可以用一个外部声明来做和原函数相同的事,但是这样做不方便(同时太慢)。
(引用函数本身的其他方法是使用arguments.callee,这种方法比较常见<不知道这么翻译对不对>,并且在严格模式中不支持)。
实际上,javaScript对两种函数声明方法对待不同。这是一个函数声明:
function abc(){}
这里的abc在目前的范围中是处处都有定义的:
// We can call it here abc(); // Works // Yet, it is defined down there. function abc(){} // We can call it again abc(); // Works
同样,它也会透过一个return语句被提前定义:
// We can call it here abc(); // Works return; function abc(){}
另外一个函数表达式:
var xyz = function(){};
这里的xyz在声明行被定义:
// We can't call it here xyz(); // UNDEFINED!!! // Now it is defined xyz = function(){} // We can call it here xyz(); // works
对函数(function)表达式和函数(Function)声明,我更倾向 "函数表达式" 声明(第一种方式),因为这种方式我可以控制可见性。当我定义这样一个函数:
var abc = function(){};
我知道我定义了一个局部函数。当我定义一个这样的函数:
abc = function(){};
我知道我定义了一个全局函数,并且我没有在作用域链的任何位置定义abc<不太清楚如何翻译>。然而像下面的定义方式:
function abc(){};
取决于上下文并且可能会让你猜测该函数真实定义的地方,特别是在使用eval()方法的时候——答案是:依赖于其所在的浏览器。
----知乎上的回答----
链接:https://www.zhihu.com/question/19878052/answer/32361868
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
the Google style guide 建议我们采用方法一。
简单的说 如果我们使用 匿名函数
var FUNCTION_NAME = function() { /* FUNCTION_BODY */};
这种方式, 编译后变量声明FUNCTION_NAME 会“被提前”了,但是他的赋值(也就是FUNCTION_BODY)并不会被提前。
也就是,匿名函数只有在被调用时才被初始化。
如果我们使用
function FUNCTION_NAME ()
{ /* FUNCTION_BODY */};
这种方式, 编译后函数声明和他的赋值都会被提前。
也就是说函数声明过程在整个程序执行之前的预处理就完成了,所以只要处于同一个作用域,就可以访问到,即使在定义之前调用它也可以。
请先看一个例子
function hereOrThere() { //function statement
return 'here';
}
alert(hereOrThere()); // alerts 'there'
function hereOrThere() {
return 'there';
}
我们会发现alert(hereOrThere) 语句执行时会alert('there')!这里的行为其实非常出乎意料,主要原因是JavaScript 函数声明的“提前”行为,简而言之,就是Javascript允许我们在变量和函数被声明之前使用它们,而第二个定义覆盖了第一种定义。换句话说,上述代码编译之后相当于
function hereOrThere() { //function statement
return 'here';
}
function hereOrThere() {//申明前置了,但因为这里的申明和赋值在一起,所以一起前置
return 'there';
}
alert(hereOrThere()); // alerts 'there'
强烈推荐阅读下面文章,JavaScript 中对变量和函数声明的“提前(hoist)”
再看下面一个例子:
var hereOrThere = function() { // function expression
return 'here';
};
alert(hereOrThere()); // alerts 'here'
hereOrThere = function() {
return 'there';
};
var hereOrThere;//申明前置了
hereOrThere = function() { // function expression
return 'here';
};
alert(hereOrThere()); // alerts 'here'
hereOrThere = function() {
return 'there';
};
参考 Frequently Misunderstood JavaScript Concepts The Syntax for Defining a Function is Significant