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

    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(){};
  • 相关阅读:
    字符编码相关
    函数之形参与实参
    文件操作模式
    函数对象,名称空间,作用域,和闭包
    吴裕雄天生自然SPRINGBOOT开发实战处理'spring.datasource.url' is not specified and no embedded datasource could be autoconfigured
    吴裕雄天生自然SPRINGBOOT开发实战处理XXXX that could not be found.
    吴裕雄天生自然SPRINGBOOT开发实战SpringBoot HTML表单登录
    吴裕雄天生自然SPRINGBOOT开发实战SpringBoot REST示例
    吴裕雄天生自然SpringBoot开发实战学习笔记处理 Could not write metadata for '/Servers'.metadata\.plugins\org.eclipse.core.resources\.projects\Servers\.markers.snap (系统找不到指定的路径。)
    吴裕雄天生自然SPRINGBOOT开发实战SpringBoot Tomcat部署
  • 原文地址:https://www.cnblogs.com/Fooo/p/9212315.html
Copyright © 2011-2022 走看看