zoukankan      html  css  js  c++  java
  • js中 var functionName = function() {} 和 function functionName() {} 两种函数声明的区别 (译)

    stackOverflow中看到了很久以前问的一个关于函数声明的问题,问题对函数剖析的特别深。这里翻译了一下组织成一篇小博文,加深一下对这两种声明方式的印象。虽是老调重弹,但是只要能帮助理解问题,不管多老,都是好的。

    问:

    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()方法的时候——答案是:依赖于其所在的浏览器。

    问题地址:http://stackoverflow.com/questions/336859/var-functionname-function-vs-function-functionname

    翻译的不好,请勿拍!

  • 相关阅读:
    事件
    dom对象
    逻辑运算和作用域的问题
    json
    数组
    字符串
    函数
    js的数据类型和全局方法
    js
    10.16 js内容
  • 原文地址:https://www.cnblogs.com/alkq1989/p/5556771.html
Copyright © 2011-2022 走看看