代码之家  ›  专栏  ›  技术社区  ›  Richard Garside

var functionname=function()vs function functionname()

  •  6312
  • Richard Garside  · 技术社区  · 16 年前

    我最近开始维护别人的javascript代码。我正在修复bug,添加特性,还试图整理代码并使其更加一致。

    前一个开发人员使用两种方法来声明函数,我无法确定函数背后是否有原因。

    这两种方法是:

    var functionOne = function() {
        // Some code
    };
    
    function functionTwo() {
        // Some code
    }
    

    使用这两种不同方法的原因是什么?每种方法的优缺点是什么?有什么方法可以用一种方法做,而不能用另一种方法做吗?

    37 回复  |  直到 16 年前
        1
  •  4686
  •   Sid Vishnoi Sumit Das    7 年前

    区别在于 functionOne 是一个函数表达式,因此只在到达该行时定义,而 functionTwo 是一个函数声明,并在执行其周围的函数或脚本(由于 hoisting )

    例如,函数表达式:

    // TypeError: functionOne is not a function
    functionOne();
    
    var functionOne = function() {
      console.log("Hello!");
    };

    以及函数声明:

    // Outputs: "Hello!"
    functionTwo();
    
    function functionTwo() {
      console.log("Hello!");
    }

    这也意味着您不能使用函数声明有条件地定义函数:

    if (test) {
       // Error or misbehavior
       function functionThree() { doSomething(); }
    }
    

    上面实际上定义了 functionThree 不管 test 的值-除非 use strict 实际上,在这种情况下,它只会引发一个错误。

        2
  •  1851
  •   Merlin    8 年前

    首先我想纠正格雷格: function abc(){} 也是作用域-名称 abc 在遇到此定义的范围中定义。例子:

    function xyz(){
      function abc(){};
      // abc is defined here...
    }
    // ...but not here
    

    其次,可以将这两种风格结合起来:

    var xyz = function abc(){};
    

    xyz 像往常一样定义, abc 在所有浏览器中都未定义,但Internet Explorer-不要依赖正在定义的浏览器。但它将在其体内被定义为:

    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”属性( Internet Explorer不支持 )基本上当你定义一个函数

    function abc(){};
    console.log(abc.name); // prints "abc"
    

    它的名称是自动分配的。但是当你把它定义成

    var abc = function(){};
    console.log(abc.name); // prints ""
    

    它的名称是空的——我们创建了一个匿名函数,并将它赋给了某个变量。

    使用组合样式的另一个好理由是使用短的内部名称引用自身,同时为外部用户提供一个长的、无冲突的名称:

    // Assume really.long.external.scoped is {}
    really.long.external.scoped.name = function shortcut(n){
      // Let it call itself recursively:
      shortcut(n - 1);
      // ...
      // Let it 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
    

    函数声明与函数表达式是Greg证明存在差异的真正原因。

    有趣的事实:

    var xyz = function abc(){};
    console.log(xyz.name); // Prints "abc"
    

    我个人更喜欢“函数表达式”声明,因为这样我可以控制可见性。当我把函数定义为

    var abc = function(){};
    

    我知道我在本地定义了函数。当我把函数定义为

    abc = function(){};
    

    我知道我在全球范围内定义它,前提是我没有定义 abc 范围链中的任何地方。这种类型的定义即使在内部使用也很有弹性 eval() . 而定义

    function abc(){};
    

    取决于上下文,可能会让您猜测它的实际定义,尤其是在 表达式() -答案是:这取决于浏览器。

        3
  •  577
  •   T.J. Crowder    6 年前

    下面是创建函数的标准表单的概要: (最初是为另一个问题写的,但在进入规范问题后进行了修改。)

    条款:

    快速清单:

    • 函数声明

    • “匿名” function 表情 (尽管使用了术语,但有时会创建具有名称的函数)

    • 命名 功能 表情

    • 访问器函数初始值设定项(ES5+)

    • 箭头函数表达式(ES2015+) (与匿名函数表达式一样,它不涉及显式名称,但可以创建具有名称的函数)

    • 对象初始值设定项(ES2015+)中的方法声明

    • 中的构造函数和方法声明 class (ES2015)

    函数声明

    第一种形式是 函数声明 ,如下所示:

    function x() {
        console.log('x');
    }
    

    函数声明是 宣言 它不是语句或表达式。因此,你不能用 ; (尽管这样做是无害的)。

    当执行进入其出现的上下文时,将处理函数声明, 之前 执行任何分步代码。它创建的函数有一个正确的名称( x 在上面的示例中),该名称将放在声明出现的范围中。

    因为它是在同一上下文中的任何逐步代码之前处理的,所以您可以这样做:

    x(); // Works even though it's above the declaration
    function x() {
        console.log('x');
    }
    

    在ES2015之前,如果您将一个函数声明放在一个类似于 try , if , switch , while 等等,像这样:

    if (someCondition) {
        function foo() {    // <===== HERE THERE
        }                   // <===== BE DRAGONS
    }
    

    因为它们被处理过 之前 一步一步地运行代码,当它们处于控制结构中时,很难知道该怎么做。

    尽管这样做不是 明确规定 在ES2015年之前, 允许延伸 支持块中的函数声明。不幸的是(不可避免的),不同的引擎做了不同的事情。

    截至ES2015年,规范规定了该做什么。实际上,它提供了三个单独的任务:

    1. 如果处于松散模式 在Web浏览器上,javascript引擎应该做一件事
    2. 如果在Web浏览器上处于松散模式,则javascript引擎应该执行其他操作。
    3. 如果在 严格的 模式(浏览器与否),javascript引擎应该做另一件事

    松散模式的规则很复杂,但是 严格的 模式,块中的函数声明很容易:它们是块的本地声明(它们有 块范围 在ES2015年也是新的),它们被吊到了大楼的顶部。所以:

    "use strict";
    if (someCondition) {
        foo();               // Works just fine
        function foo() {
        }
    }
    console.log(typeof foo); // "undefined" (`foo` is not in scope here
                             // because it's not in the same block)
    

    “匿名” 功能 表情

    第二种常见形式称为 匿名函数表达式 :

    var y = function () {
        console.log('y');
    };
    

    与所有表达式一样,它是在代码的逐步执行过程中到达时进行计算的。

    在ES5中,此创建的函数没有名称(它是匿名的)。在ES2015中,如果可能的话,通过从上下文推断函数来为其分配名称。在上面的示例中,名称为 y . 当函数是属性初始值设定项的值时,会执行类似的操作。(有关此情况发生的时间和规则的详细信息,请搜索 SetFunctionName the specification -它出现了 遍及 这个地方。

    命名 功能 表情

    第三种形式是 命名函数表达式 (NFE):

    var z = function w() {
        console.log('zw')
    };
    

    此创建的函数具有正确的名称( w 在这种情况下)。与所有表达式一样,在代码的逐步执行中达到此值时,将对其进行计算。函数的名称是 添加到表达式出现的范围;名称 在函数本身的范围内:

    var z = function w() {
        console.log(typeof w); // "function"
    };
    console.log(typeof w);     // "undefined"
    

    注意,NFE经常是JavaScript实现中的错误源。例如,IE8和更早版本处理NFE completely incorrectly ,在两个不同的时间创建两个不同的函数。早期版本的Safari也有问题。好消息是,当前版本的浏览器(IE9和更高版本,当前的Safari)不再有这些问题。(但遗憾的是,截至本文撰写之时,IE8仍在广泛使用,因此将NFE与Web代码结合使用仍然存在问题。)

    访问器函数初始值设定项(ES5+)

    有时函数可以潜入,但基本上没有被注意到;这就是 存取函数 . 下面是一个例子:

    var obj = {
        value: 0,
        get f() {
            return this.value;
        },
        set f(v) {
            this.value = v;
        }
    };
    console.log(obj.f);         // 0
    console.log(typeof obj.f);  // "number"
    

    注意,当我使用函数时,我没有使用 () !那是因为它是一个 访问函数 为了一个财产。我们以正常的方式获取和设置属性,但是在幕后,函数被调用。

    还可以使用创建访问器函数 Object.defineProperty , Object.defineProperties 以及不太为人所知的第二个论点 Object.create .

    箭头函数表达式(ES2015+)

    ES2015为我们带来了 箭头函数 . 以下是一个例子:

    var a = [1, 2, 3];
    var b = a.map(n => n * 2);
    console.log(b.join(", ")); // 2, 4, 6
    

    看到那个 n => n * 2 藏在里面的东西 map() 打电话?这是一个函数。

    关于arrow函数的一些事情:

    1. 他们没有自己的 this . 相反,他们 关闭 这个 它们被定义的上下文。(他们也关闭了 arguments 如果相关的话, super 这意味着 它们内部与 它们的创建位置,不能更改。

    2. 正如你已经注意到的,你不使用关键字 功能 ;相反,您使用 => .

    这个 n=& gt;n* 2 上面的例子是它们的一种形式。如果有多个参数要传递函数,则使用parens:

    var a = [1, 2, 3];
    var b = a.map((n, i) => n * i);
    console.log(b.join(", ")); // 0, 2, 6
    

    (记住 Array#map 将条目作为第一个参数传递,将索引作为第二个参数传递。)

    在这两种情况下,函数的主体只是一个表达式;函数的返回值将自动是该表达式的结果(不使用显式的 return )

    如果你做的不仅仅是一个表达式,使用 {} 和明确的 返回 (如果需要返回值),正常情况下:

    var a = [
      {first: "Joe", last: "Bloggs"},
      {first: "Albert", last: "Bloggs"},
      {first: "Mary", last: "Albright"}
    ];
    a = a.sort((a, b) => {
      var rv = a.last.localeCompare(b.last);
      if (rv === 0) {
        rv = a.first.localeCompare(b.first);
      }
      return rv;
    });
    console.log(JSON.stringify(a));
    

    没有的版本 { ... } 被称为箭头函数 表达体 简洁的身体 . (也:A 简洁的 箭头功能。)带有 {…} 定义主体是一个带有 功能体 . (也:A 冗长的 箭头函数。)

    对象初始值设定项(ES2015+)中的方法声明

    ES2015允许以较短的形式声明引用名为 方法定义 ;如下所示:

    var o = {
        foo() {
        }
    };
    

    ES5及更早版本中几乎等同于:

    var o = {
        foo: function foo() {
        }
    };
    

    区别在于(除了冗长的内容)一个方法可以使用 超级的 ,但函数不能。例如,如果您有一个定义了的对象(例如) valueOf 使用方法语法,它可以使用 super.valueOf() 为了得到价值 Object.prototype.valueOf 可能会返回(在用它做其他事情之前),而ES5版本必须返回 Object.prototype.valueOf.call(this) 相反。

    这也意味着该方法具有对其定义的对象的引用,因此如果该对象是临时的(例如,将其传递给 Object.assign 作为源对象之一),方法语法 能够 意味着当对象可能被垃圾收集时,它会被保留在内存中(如果javascript引擎没有检测到这种情况,并且如果没有任何方法使用它,就处理它 超级的 )

    中的构造函数和方法声明 (ES2015)

    ES2015带给我们 语法,包括声明的构造函数和方法:

    class Person {
        constructor(firstName, lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
    
        getFullName() {
            return this.firstName + " " + this.lastName;
        }
    }
    

    上面有两个函数声明:一个用于构造函数,它获取名称 Person 一个 getFullName ,这是分配给 Person.prototype .

        4
  •  138
  •   Community CDub    8 年前

    谈到全球环境,两者都是 var 语句与A FunctionDeclaration 最后将创建一个 不可删除的 全局对象的属性,但 可以被覆盖 .

    这两种方法之间的细微差别在于 Variable Instantiation 进程运行(在实际代码执行之前)用 var 将用初始化 undefined 以及 函数声明 从那一刻起,S将可用,例如:

     alert(typeof foo); // 'function', it's already available
     alert(typeof bar); // 'undefined'
     function foo () {}
     var bar = function () {};
     alert(typeof bar); // 'function'
    

    转让 bar FunctionExpression 在运行时发生。

    由创建的全局属性 函数声明 可以覆盖,而不会出现任何问题,就像变量值一样,例如:

     function test () {}
     test = null;
    

    两个示例之间的另一个明显区别是,第一个函数没有名称,但第二个函数有名称,这在调试(即检查调用堆栈)时非常有用。

    关于您编辑的第一个示例( foo = function() { alert('hello!'); }; )这是一个未声明的任务,我强烈建议您始终使用 var 关键字。

    有任务,没有 var 语句,如果在作用域链中找不到引用的标识符,它将成为 可删除的 全局对象的属性。

    另外,未声明的工作分配 ReferenceError 在下面的ecmascript 5上 Strict Mode .

    必须阅读:

    注释 :此答案已合并自 another question 其中,OP的主要疑问和误解是,标识符声明为 函数声明 ,无法覆盖,情况并非如此。

        5
  •  116
  •   Peter Mortensen icecrime    9 年前

    您在那里发布的两个代码片段在几乎所有目的上都将以相同的方式运行。

    然而,行为上的区别在于第一种变体( var functionOne = function() {} ,该函数只能在代码中的该点之后调用。

    第二种变体( function functionTwo() ,函数可用于在上面声明函数的代码。

    这是因为对于第一个变量,函数被分配给变量 foo 在运行时。在第二个函数中,函数被分配给该标识符, ,在分析时。

    更多技术信息

    javascript有三种定义函数的方法。

    1. 您的第一个代码片段显示 函数表达式 . 这涉及到使用 “函数”运算符 创建一个函数-该运算符的结果可以存储在任何变量或对象属性中。函数表达式就是这样强大的。函数表达式通常称为“匿名函数”,因为它不必有名称,
    2. 第二个例子是 函数声明 . 这使用了 “功能”声明 创建一个函数。函数在解析时可用,可以在该范围内的任何地方调用。以后仍可以将其存储在变量或对象属性中。
    3. 定义函数的第三种方法是 “function()”构造函数 ,这在您的原始日志中没有显示。不建议使用它,因为它的工作方式与 eval() 这是有问题的。
        6
  •  97
  •   Community CDub    8 年前

    更好的解释 Greg's answer

    functionTwo();
    function functionTwo() {
    }
    

    为什么没有错误?我们一直被教导,表达是自上而下执行的。?)

    因为:

    始终移动函数声明和变量声明( hoisted )通过javascript解释器将其隐藏到其包含范围的顶部。显然,函数参数和语言定义的名称已经存在。 ben cherry

    这意味着这样的代码:

    functionOne();                  ---------------      var functionOne;
                                    | is actually |      functionOne();
    var functionOne = function(){   | interpreted |-->
    };                              |    like     |      functionOne = function(){
                                    ---------------      };
    

    注意声明的分配部分没有被提升。只有名字被提升。

    但在有函数声明的情况下,整个函数体也将被提升 :

    functionTwo();              ---------------      function functionTwo() {
                                | is actually |      };
    function functionTwo() {    | interpreted |-->
    }                           |    like     |      functionTwo();
                                ---------------
    
        7
  •  88
  •   ROMANIA_engineer Alexey    10 年前

    其他评论者已经讨论了上述两种变体的语义差异。我想指出一个风格上的区别:只有“赋值”变体可以设置另一个对象的属性。

    我经常用这样的模式构建JavaScript模块:

    (function(){
        var exports = {};
    
        function privateUtil() {
                ...
        }
    
        exports.publicUtil = function() {
                ...
        };
    
        return exports;
    })();
    

    使用这种模式,公共函数将全部使用赋值,而私有函数使用声明。

    (还请注意,赋值应该在语句后使用分号,而声明禁止使用分号。)

        8
  •  74
  •   Alireza    8 年前

    当您需要避免重写函数以前的定义时,可以说明何时首选第一个方法而不是第二个方法。

    if (condition){
        function myfunction(){
            // Some code
        }
    }
    

    ,此定义 myfunction 将重写任何以前的定义,因为它将在解析时完成。

    同时

    if (condition){
        var myfunction = function (){
            // Some code
        }
    }
    

    定义是否正确 肌力函数 只有当 condition 得到满足。

        9
  •  60
  •   Community CDub    8 年前

    一个重要的原因是添加一个而且只有一个变量作为名称空间的“根”…

    var MyNamespace = {}
    MyNamespace.foo= function() {
    
    }
    

    var MyNamespace = {
      foo: function() {
      },
      ...
    }
    

    名称间距有很多种技术。随着大量可用的javascript模块的出现,它变得更加重要。

    也看到 How do I declare a namespace in JavaScript?

        10
  •  52
  •   Yash    7 年前

    Hoisting 是javascript解释器将所有变量和函数声明移动到当前作用域顶部的操作。

    但是,只悬挂实际申报。把任务留在原地。

    • 页面中声明的变量/函数是全局变量,可以访问该页面中的任何位置。
    • 函数内声明的变量/函数具有局部作用域。表示它们在函数体(作用域)内可用/访问,在函数体外不可用。

    Variable

    JavaScript被称为松散类型语言。这意味着javascript变量可以保存 Data-Type . javascript会根据运行时提供的值/文字自动更改变量类型。

    global_Page = 10;                                               var global_Page;      « undefined
        « Integer literal, Number Type.   -------------------       global_Page = 10;     « Number         
    global_Page = 'Yash';                 |   Interpreted   |       global_Page = 'Yash'; « String
        « String literal, String Type.    «       AS        «       global_Page = true;   « Boolean 
    var global_Page = true;               |                 |       global_Page = function (){          « function
        « Boolean Type                    -------------------                 var local_functionblock;  « undefined
    global_Page = function (){                                                local_functionblock = 777;« Number
        var local_functionblock = 777;                              };  
        // Assigning function as a data.
    };  
    

    功能

    function Identifier_opt ( FormalParameterList_opt ) { 
          FunctionBody | sequence of statements
    
          « return;  Default undefined
          « return 'some data';
    }
    
    • 页面内声明的函数被提升到具有全局访问权限的页面顶部。
    • 函数块内声明的函数将被提升到块的顶部。
    • 函数的默认返回值为' undefined ', Variable 声明默认值也为“未定义”

      Scope with respect to function-block global. 
      Scope with respect to page undefined | not available.
      

    函数声明

    function globalAccess() {                                  function globalAccess() {      
    }                                  -------------------     }
    globalAccess();                    |                 |     function globalAccess() { « Re-Defined / overridden.
    localAccess();                     «   Hoisted  As   «         function localAccess() {
    function globalAccess() {          |                 |         }
         localAccess();                -------------------         localAccess(); « function accessed with in globalAccess() only.
         function localAccess() {                              }
         }                                                     globalAccess();
    }                                                          localAccess(); « ReferenceError as the function is not defined
    

    函数表达式

            10;                 « literal
           (10);                « Expression                (10).toString() -> '10'
    var a;                      
        a = 10;                 « Expression var              a.toString()  -> '10'
    (function invoke() {        « Expression Function
     console.log('Self Invoking');                      (function () {
    });                                                               }) () -> 'Self Invoking'
    
    var f; 
        f = function (){        « Expression var Function
        console.log('var Function');                                   f ()  -> 'var Function'
        };
    

    分配给变量的函数示例:

    (function selfExecuting(){
        console.log('IIFE - Immediately-Invoked Function Expression');
    }());
    
    var anonymous = function (){
        console.log('anonymous function Expression');
    };
    
    var namedExpression = function for_InternalUSE(fact){
        if(fact === 1){
            return 1;
        }
    
        var localExpression = function(){
            console.log('Local to the parent Function Scope');
        };
        globalExpression = function(){ 
            console.log('creates a new global variable, then assigned this function.');
        };
    
        //return; //undefined.
        return fact * for_InternalUSE( fact - 1);   
    };
    
    namedExpression();
    globalExpression();
    

    javascript解释为

    var anonymous;
    var namedExpression;
    var globalExpression;
    
    anonymous = function (){
        console.log('anonymous function Expression');
    };
    
    namedExpression = function for_InternalUSE(fact){
        var localExpression;
    
        if(fact === 1){
            return 1;
        }
        localExpression = function(){
            console.log('Local to the parent Function Scope');
        };
        globalExpression = function(){ 
            console.log('creates a new global variable, then assigned this function.');
        };
    
        return fact * for_InternalUSE( fact - 1);    // DEFAULT UNDEFINED.
    };
    
    namedExpression(10);
    globalExpression();
    

    您可以检查函数声明,表达式测试不同浏览器的使用 jsperf Test Runner


    ES5 Constructor Function Classes :使用function.prototype.bind创建的函数对象

    javascript将函数视为第一类对象,因此作为一个对象,您可以为函数分配属性。

    function Shape(id) { // Function Declaration
        this.id = id;
    };
        // Adding a prototyped method to a function.
        Shape.prototype.getID = function () {
            return this.id;
        };
        Shape.prototype.setID = function ( id ) {
            this.id = id;
        };
    
    var expFn = Shape; // Function Expression
    
    var funObj = new Shape( ); // Function Object
    funObj.hasOwnProperty('prototype'); // false
    funObj.setID( 10 );
    console.log( funObj.getID() ); // 10
    

    引入ES6 箭头函数 :箭头函数表达式的语法较短,最适合非方法函数,不能用作构造函数。

    ArrowFunction : ArrowParameters => ConciseBody .

    const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; };
    console.log( fn(2) ); // Even
    console.log( fn(3) ); // Odd
    
        11
  •  36
  •   Leon Gaban    10 年前

    我在补充我自己的答案,只是因为其他人都彻底地覆盖了起重部分。

    很长一段时间以来,我一直想知道哪条路更好,多亏了 http://jsperf.com 现在我知道:

    enter image description here

    函数声明 更快,这就是Web开发中真正重要的东西,对吗?;)

        12
  •  32
  •   eljenso    12 年前

    一旦建立绑定,分配给变量的函数声明和函数表达式的行为就相同。

    但是在 怎样 什么时候? 函数对象实际上与其变量相关联。这种差异是由于 变量提升 在JavaScript中。

    基本上,所有函数声明和变量声明都被提升到 功能 声明发生的地方(这就是为什么我们说javascript 功能范围 )

    • 当函数声明被提升时,函数体“跟随” 因此,当对函数体进行计算时,变量将立即 绑定到函数对象。

    • 当提升变量声明时,初始化将执行 跟随,但被“落在后面”。变量初始化为 undefined 在函数体的开始处, 分配 代码中原始位置的值。(实际上,它将在 每一个 发生同名变量声明的位置。)

    提升的顺序也很重要:函数声明优先于同名的变量声明,最后一个函数声明优先于同名的前一个函数声明。

    一些例子…

    var foo = 1;
    function bar() {
      if (!foo) {
        var foo = 10 }
      return foo; }
    bar() // 10
    

    变量 foo 被提升到函数的顶部,初始化为 未定义 ,这样 !foo true 如此 被指派 10 . 这个 在外面 bar 的作用域不起任何作用,也不会受到影响。

    function f() {
      return a; 
      function a() {return 1}; 
      var a = 4;
      function a() {return 2}}
    f()() // 2
    
    function f() {
      return a;
      var a = 4;
      function a() {return 1};
      function a() {return 2}}
    f()() // 2
    

    函数声明优先于变量声明,最后一个函数声明“stick”。

    function f() {
      var a = 4;
      function a() {return 1}; 
      function a() {return 2}; 
      return a; }
    f() // 4
    

    在这个例子中 a 用计算第二个函数声明所得的函数对象初始化,然后分配 4 .

    var a = 1;
    function b() {
      a = 10;
      return;
      function a() {}}
    b();
    a // 1
    

    这里首先提升函数声明,声明并初始化变量 . 接下来,这个变量被赋值 . 换句话说:赋值不赋值给外部变量 .

        13
  •  30
  •   sla55er    10 年前

    第一个示例是函数声明:

    function abc(){}
    

    第二个例子是函数表达式:

    var abc = function() {};
    

    主要区别在于它们的提升(提升和申报)方式。在第一个示例中,将提升整个函数声明。在第二个例子中,只有var'abc'被提升,它的值(函数)将不被定义,并且函数本身保持在它被声明的位置。

    简单来说:

    //this will work
    abc(param);
    function abc(){}
    
    //this would fail
    abc(param);
    var abc = function() {}
    

    为了进一步研究这个话题,我强烈推荐你 link

        14
  •  28
  •   Peter Mortensen icecrime    9 年前

    在代码维护成本方面,命名函数更可取:

    • 独立于申报地(但仍受范围限制)。
    • 更能抵抗条件初始化之类的错误(如果愿意,您仍然可以重写)。
    • 通过单独分配本地函数和作用域功能,代码变得更加可读。通常在这个范围内,功能首先进行,然后是本地函数的声明。
    • 在调试器中,您将清楚地看到调用堆栈上的函数名,而不是“匿名/评估”函数。

    我怀疑后面还有更多的命名函数的优点。而被列为命名函数的优点的是匿名函数的缺点。

    从历史上看,匿名函数是由于javascript无法作为一种语言列出具有命名函数的成员:

    {
        member:function() { /* How do I make "this.member" a named function? */
        }
    }
    
        15
  •  24
  •   Peter Mortensen icecrime    9 年前

    我在代码中使用变量方法有一个非常具体的原因,上面抽象地介绍了它的理论,但是一个例子可能会帮助像我这样的人,因为JavaScript专业知识有限。

    我有一些代码需要使用160个独立设计的品牌来运行。大多数代码都在共享文件中,但是特定于品牌的东西在一个单独的文件中,每个品牌对应一个文件。

    有些品牌需要特定的功能,有些则不需要。有时我必须添加新的功能来执行新的品牌特定的事情。我很乐意更改共享代码,但我不想更改所有160组品牌文件。

    通过使用变量语法,我可以在共享代码中声明变量(本质上是一个函数指针),并分配一个普通的存根函数,或者设置为空。

    然后,需要特定实现函数的一个或两个Brandings可以定义函数的版本,并根据需要将其分配给变量,其余的什么也不做。我可以在共享代码中执行空函数之前测试它。

    从上面的人们的评论中,我认为重新定义一个静态函数也是可能的,但是我认为变量解是好的和清晰的。

        16
  •  22
  •   ROMANIA_engineer Alexey    10 年前

    在计算机科学术语中,我们讨论匿名函数和命名函数。我认为最重要的区别是一个匿名函数没有绑定到一个名称,因此这个名称是匿名函数。在JavaScript中,它是在运行时动态声明的第一类对象。

    有关匿名函数和lambda微积分的更多信息,维基百科是一个很好的开始。( http://en.wikipedia.org/wiki/Anonymous_function )

        17
  •  22
  •   Community CDub    8 年前

    Greg's Answer 已经够好了,但我还是想增加一些我刚刚学过的东西 Douglas Crockford's 视频。

    函数表达式:

    var foo = function foo() {};
    

    函数语句:

    function foo() {};
    

    函数语句只是 var 带有 function 价值。

    所以

    函数foo()
    

    扩展到

    var foo=函数foo()
    

    进一步扩展到:

    var foo = undefined;
    foo = function foo() {};
    

    它们都被提升到代码的顶端。

    Screenshot from video

        18
  •  18
  •   Community CDub    8 年前

    @EugeneLazutkin 举个例子 names an assigned function to be able to use shortcut() 作为对自身的内部引用。 John Resig 给出了另一个例子- 复制分配给另一个对象的递归函数 在他的 Learning Advanced Javascript 辅导的。虽然在这里将函数分配给属性并不是一个严格的问题,但我建议您积极尝试本教程-通过单击右上角的按钮来运行代码,然后双击代码以根据您的喜好进行编辑。

    教程中的示例:递归调用 yell() :

    Tests fail when the original ninja object is removed. (第13页)

    var ninja = { 
      yell: function(n){ 
        return n > 0 ? ninja.yell(n-1) + "a" : "hiy"; 
      } 
    }; 
    assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." ); 
    
    var samurai = { yell: ninja.yell }; 
    var ninja = null; 
    
    try { 
      samurai.yell(4); 
    } catch(e){ 
      assert( false, "Uh, this isn't good! Where'd ninja.yell go?" ); 
    }
    

    If you name the function that will be called recursively, the tests will pass. (第14页)

    var ninja = { 
      yell: function yell(n){ 
        return n > 0 ? yell(n-1) + "a" : "hiy"; 
      } 
    }; 
    assert( ninja.yell(4) == "hiyaaaa", "Works as we would expect it to!" ); 
    
    var samurai = { yell: ninja.yell }; 
    var ninja = {}; 
    assert( samurai.yell(4) == "hiyaaaa", "The method correctly calls itself." );
    
        19
  •  16
  •   Ingo Kegel    12 年前

    其他答案中没有提到的另一个区别是,如果使用匿名函数

    var functionOne = function() {
        // Some code
    };
    

    并将其用作构造函数

    var one = new functionOne();
    

    然后 one.constructor.name 不会被定义。 Function.name 是非标准的,但受Firefox、Chrome、其他Webkit衍生浏览器和IE 9+支持。

    function functionTwo() {
        // Some code
    }
    two = new functionTwo();
    

    可以使用 two.constructor.name .

        20
  •  14
  •   Pawel Furmaniak    11 年前

    如果要使用这些函数创建对象,您将得到:

    var objectOne = new functionOne();
    console.log(objectOne.__proto__); // prints "Object {}" because constructor is an anonymous function
    
    var objectTwo = new functionTwo();
    console.log(objectTwo.__proto__); // prints "functionTwo {}" because constructor is a named function
    
        21
  •  14
  •   Peter Mortensen icecrime    9 年前

    第一个(函数dosomething(x))应该是对象符号的一部分。

    第二个( var doSomething = function(x){ alert(x);} )只是创建一个匿名函数并将其分配给一个变量, doSomething . 所以dosomething()将调用函数。

    你可能想知道 函数声明 函数表达式 是。

    函数声明定义一个命名的函数变量,而不需要变量赋值。函数声明作为独立结构出现,不能嵌套在非函数块中。

    function foo() {
        return 3;
    }
    

    ECMA 5(13.0)将语法定义为
    函数标识符(formlParameterList 选择 )功能体

    在上述条件下,函数名在其作用域和其父级作用域内可见(否则将无法访问)。

    在函数表达式中

    函数表达式将函数定义为较大表达式语法(通常是变量赋值)的一部分。通过函数表达式定义的函数可以命名或匿名。函数表达式不应以__函数__开头。

    // Anonymous function expression
    var a = function() {
        return 3;
    }
    
    // Named function expression
    var a = function foo() {
        return 3;
    }
    
    // Self-invoking function expression
    (function foo() {
        alert("hello!");
    })();
    

    ECMA 5(13.0)将语法定义为
    函数标识符 选择 (格式参数列表 选择 )功能体

        22
  •  14
  •   Peter Mortensen icecrime    9 年前

    我将列出以下差异:

    1. 函数声明可以放在代码的任何地方。即使在定义出现在代码中之前调用它,它也会在将函数声明提交到内存或以提升的方式执行时执行,而页面中的任何其他代码都将开始执行。

      请看下面的函数:

      function outerFunction() {
          function foo() {
             return 1;
          }
          return foo();
          function foo() {
             return 2;
          }
      }
      alert(outerFunction()); // Displays 2
      

      这是因为,在执行过程中,它看起来像:

      function foo() {  // The first function declaration is moved to top
          return 1;
      }
      function foo() {  // The second function declaration is moved to top
          return 2;
      }
      function outerFunction() {
          return foo();
      }
      alert(outerFunction()); //So executing from top to bottom,
                              //the last foo() returns 2 which gets displayed
      

      如果函数表达式在调用前未定义,则会导致错误。此外,这里的函数定义本身不会像在函数声明中那样移动到顶部或提交到内存中。但是我们分配给函数的变量被提升了, 未定义 分配给它。

      使用函数表达式的相同函数:

      function outerFunction() {
          var foo = function() {
             return 1;
          }
          return foo();
          var foo = function() {
             return 2;
          }
      }
      alert(outerFunction()); // Displays 1
      

      这是因为在执行期间,它看起来像:

      function outerFunction() {
         var foo = undefined;
         var foo = undefined;
      
         foo = function() {
            return 1;
         };
         return foo ();
         foo = function() {   // This function expression is not reachable
            return 2;
         };
      }
      alert(outerFunction()); // Displays 1
      
    2. 在非函数块中编写函数声明是不安全的,例如 如果 因为他们无法接近。

      if (test) {
          function x() { doSomething(); }
      }
      
    3. 与下面类似的命名函数表达式,在版本9之前的Internet Explorer浏览器中可能无法使用。

      var today = function today() {return new Date()}
      
        23
  •  12
  •   Jackson Ray Hamilton    10 年前

    根据“命名函数出现在堆栈跟踪中”的参数,现代的JavaScript引擎实际上非常能够表示匿名函数。

    在这篇文章中,V8、蜘蛛猴、脉轮和硝基总是用它们的名字来表示命名函数。如果一个匿名函数有标识符的话,它们几乎总是通过它的标识符来引用它。

    spidermonkey可以找出从另一个函数返回的匿名函数的名称。其余的不能。

    如果您真的非常希望迭代器和成功回调出现在跟踪中,那么您也可以将它们命名为……

    [].forEach(function iterator() {});
    

    但在很大程度上,这不值得去强调。

    挽具 Fiddle )

    'use strict';
    
    var a = function () {
        throw new Error();
    },
        b = function b() {
            throw new Error();
        },
        c = function d() {
            throw new Error();
        },
        e = {
            f: a,
            g: b,
            h: c,
            i: function () {
                throw new Error();
            },
            j: function j() {
                throw new Error();
            },
            k: function l() {
                throw new Error();
            }
        },
        m = (function () {
            return function () {
                throw new Error();
            };
        }()),
        n = (function () {
            return function n() {
                throw new Error();
            };
        }()),
        o = (function () {
            return function p() {
                throw new Error();
            };
        }());
    
    console.log([a, b, c].concat(Object.keys(e).reduce(function (values, key) {
        return values.concat(e[key]);
    }, [])).concat([m, n, o]).reduce(function (logs, func) {
    
        try {
            func();
        } catch (error) {
            return logs.concat('func.name: ' + func.name + '\n' +
                               'Trace:\n' +
                               error.stack);
            // Need to manually log the error object in Nitro.
        }
    
    }, []).join('\n\n'));
    

    V8

    func.name: 
    Trace:
    Error
        at a (http://localhost:8000/test.js:4:11)
        at http://localhost:8000/test.js:47:9
        at Array.reduce (native)
        at http://localhost:8000/test.js:44:27
    
    func.name: b
    Trace:
    Error
        at b (http://localhost:8000/test.js:7:15)
        at http://localhost:8000/test.js:47:9
        at Array.reduce (native)
        at http://localhost:8000/test.js:44:27
    
    func.name: d
    Trace:
    Error
        at d (http://localhost:8000/test.js:10:15)
        at http://localhost:8000/test.js:47:9
        at Array.reduce (native)
        at http://localhost:8000/test.js:44:27
    
    func.name: 
    Trace:
    Error
        at a (http://localhost:8000/test.js:4:11)
        at http://localhost:8000/test.js:47:9
        at Array.reduce (native)
        at http://localhost:8000/test.js:44:27
    
    func.name: b
    Trace:
    Error
        at b (http://localhost:8000/test.js:7:15)
        at http://localhost:8000/test.js:47:9
        at Array.reduce (native)
        at http://localhost:8000/test.js:44:27
    
    func.name: d
    Trace:
    Error
        at d (http://localhost:8000/test.js:10:15)
        at http://localhost:8000/test.js:47:9
        at Array.reduce (native)
        at http://localhost:8000/test.js:44:27
    
    func.name: 
    Trace:
    Error
        at e.i (http://localhost:8000/test.js:17:19)
        at http://localhost:8000/test.js:47:9
        at Array.reduce (native)
        at http://localhost:8000/test.js:44:27
    
    func.name: j
    Trace:
    Error
        at j (http://localhost:8000/test.js:20:19)
        at http://localhost:8000/test.js:47:9
        at Array.reduce (native)
        at http://localhost:8000/test.js:44:27
    
    func.name: l
    Trace:
    Error
        at l (http://localhost:8000/test.js:23:19)
        at http://localhost:8000/test.js:47:9
        at Array.reduce (native)
        at http://localhost:8000/test.js:44:27
    
    func.name: 
    Trace:
    Error
        at http://localhost:8000/test.js:28:19
        at http://localhost:8000/test.js:47:9
        at Array.reduce (native)
        at http://localhost:8000/test.js:44:27
    
    func.name: n
    Trace:
    Error
        at n (http://localhost:8000/test.js:33:19)
        at http://localhost:8000/test.js:47:9
        at Array.reduce (native)
        at http://localhost:8000/test.js:44:27
    
    func.name: p
    Trace:
    Error
        at p (http://localhost:8000/test.js:38:19)
        at http://localhost:8000/test.js:47:9
        at Array.reduce (native)
        at http://localhost:8000/test.js:44:27 test.js:42
    

    蜘蛛猴

    func.name: 
    Trace:
    a@http://localhost:8000/test.js:4:5
    @http://localhost:8000/test.js:47:9
    @http://localhost:8000/test.js:54:1
    
    
    func.name: b
    Trace:
    b@http://localhost:8000/test.js:7:9
    @http://localhost:8000/test.js:47:9
    @http://localhost:8000/test.js:54:1
    
    
    func.name: d
    Trace:
    d@http://localhost:8000/test.js:10:9
    @http://localhost:8000/test.js:47:9
    @http://localhost:8000/test.js:54:1
    
    
    func.name: 
    Trace:
    a@http://localhost:8000/test.js:4:5
    @http://localhost:8000/test.js:47:9
    @http://localhost:8000/test.js:54:1
    
    
    func.name: b
    Trace:
    b@http://localhost:8000/test.js:7:9
    @http://localhost:8000/test.js:47:9
    @http://localhost:8000/test.js:54:1
    
    
    func.name: d
    Trace:
    d@http://localhost:8000/test.js:10:9
    @http://localhost:8000/test.js:47:9
    @http://localhost:8000/test.js:54:1
    
    
    func.name: 
    Trace:
    e.i@http://localhost:8000/test.js:17:13
    @http://localhost:8000/test.js:47:9
    @http://localhost:8000/test.js:54:1
    
    
    func.name: j
    Trace:
    j@http://localhost:8000/test.js:20:13
    @http://localhost:8000/test.js:47:9
    @http://localhost:8000/test.js:54:1
    
    
    func.name: l
    Trace:
    l@http://localhost:8000/test.js:23:13
    @http://localhost:8000/test.js:47:9
    @http://localhost:8000/test.js:54:1
    
    
    func.name: 
    Trace:
    m</<@http://localhost:8000/test.js:28:13
    @http://localhost:8000/test.js:47:9
    @http://localhost:8000/test.js:54:1
    
    
    func.name: n
    Trace:
    n@http://localhost:8000/test.js:33:13
    @http://localhost:8000/test.js:47:9
    @http://localhost:8000/test.js:54:1
    
    
    func.name: p
    Trace:
    p@http://localhost:8000/test.js:38:13
    @http://localhost:8000/test.js:47:9
    @http://localhost:8000/test.js:54:1
    

    脉轮

    func.name: undefined
    Trace:
    Error
       at a (http://localhost:8000/test.js:4:5)
       at Anonymous function (http://localhost:8000/test.js:47:9)
       at Global code (http://localhost:8000/test.js:42:1)
    
    
    func.name: undefined
    Trace:
    Error
       at b (http://localhost:8000/test.js:7:9)
       at Anonymous function (http://localhost:8000/test.js:47:9)
       at Global code (http://localhost:8000/test.js:42:1)
    
    
    func.name: undefined
    Trace:
    Error
       at d (http://localhost:8000/test.js:10:9)
       at Anonymous function (http://localhost:8000/test.js:47:9)
       at Global code (http://localhost:8000/test.js:42:1)
    
    
    func.name: undefined
    Trace:
    Error
       at a (http://localhost:8000/test.js:4:5)
       at Anonymous function (http://localhost:8000/test.js:47:9)
       at Global code (http://localhost:8000/test.js:42:1)
    
    
    func.name: undefined
    Trace:
    Error
       at b (http://localhost:8000/test.js:7:9)
       at Anonymous function (http://localhost:8000/test.js:47:9)
       at Global code (http://localhost:8000/test.js:42:1)
    
    
    func.name: undefined
    Trace:
    Error
       at d (http://localhost:8000/test.js:10:9)
       at Anonymous function (http://localhost:8000/test.js:47:9)
       at Global code (http://localhost:8000/test.js:42:1)
    
    
    func.name: undefined
    Trace:
    Error
       at e.i (http://localhost:8000/test.js:17:13)
       at Anonymous function (http://localhost:8000/test.js:47:9)
       at Global code (http://localhost:8000/test.js:42:1)
    
    
    func.name: undefined
    Trace:
    Error
       at j (http://localhost:8000/test.js:20:13)
       at Anonymous function (http://localhost:8000/test.js:47:9)
       at Global code (http://localhost:8000/test.js:42:1)
    
    
    func.name: undefined
    Trace:
    Error
       at l (http://localhost:8000/test.js:23:13)
       at Anonymous function (http://localhost:8000/test.js:47:9)
       at Global code (http://localhost:8000/test.js:42:1)
    
    
    func.name: undefined
    Trace:
    Error
       at Anonymous function (http://localhost:8000/test.js:28:13)
       at Anonymous function (http://localhost:8000/test.js:47:9)
       at Global code (http://localhost:8000/test.js:42:1)
    
    
    func.name: undefined
    Trace:
    Error
       at n (http://localhost:8000/test.js:33:13)
       at Anonymous function (http://localhost:8000/test.js:47:9)
       at Global code (http://localhost:8000/test.js:42:1)
    
    
    func.name: undefined
    Trace:
    Error
       at p (http://localhost:8000/test.js:38:13)
       at Anonymous function (http://localhost:8000/test.js:47:9)
       at Global code (http://localhost:8000/test.js:42:1)
    

    硝基

    func.name: 
    Trace:
    a@http://localhost:8000/test.js:4:22
    http://localhost:8000/test.js:47:13
    reduce@[native code]
    global code@http://localhost:8000/test.js:44:33
    
    func.name: b
    Trace:
    b@http://localhost:8000/test.js:7:26
    http://localhost:8000/test.js:47:13
    reduce@[native code]
    global code@http://localhost:8000/test.js:44:33
    
    func.name: d
    Trace:
    d@http://localhost:8000/test.js:10:26
    http://localhost:8000/test.js:47:13
    reduce@[native code]
    global code@http://localhost:8000/test.js:44:33
    
    func.name: 
    Trace:
    a@http://localhost:8000/test.js:4:22
    http://localhost:8000/test.js:47:13
    reduce@[native code]
    global code@http://localhost:8000/test.js:44:33
    
    func.name: b
    Trace:
    b@http://localhost:8000/test.js:7:26
    http://localhost:8000/test.js:47:13
    reduce@[native code]
    global code@http://localhost:8000/test.js:44:33
    
    func.name: d
    Trace:
    d@http://localhost:8000/test.js:10:26
    http://localhost:8000/test.js:47:13
    reduce@[native code]
    global code@http://localhost:8000/test.js:44:33
    
    func.name: 
    Trace:
    i@http://localhost:8000/test.js:17:30
    http://localhost:8000/test.js:47:13
    reduce@[native code]
    global code@http://localhost:8000/test.js:44:33
    
    func.name: j
    Trace:
    j@http://localhost:8000/test.js:20:30
    http://localhost:8000/test.js:47:13
    reduce@[native code]
    global code@http://localhost:8000/test.js:44:33
    
    func.name: l
    Trace:
    l@http://localhost:8000/test.js:23:30
    http://localhost:8000/test.js:47:13
    reduce@[native code]
    global code@http://localhost:8000/test.js:44:33
    
    func.name: 
    Trace:
    http://localhost:8000/test.js:28:30
    http://localhost:8000/test.js:47:13
    reduce@[native code]
    global code@http://localhost:8000/test.js:44:33
    
    func.name: n
    Trace:
    n@http://localhost:8000/test.js:33:30
    http://localhost:8000/test.js:47:13
    reduce@[native code]
    global code@http://localhost:8000/test.js:44:33
    
    func.name: p
    Trace:
    p@http://localhost:8000/test.js:38:30
    http://localhost:8000/test.js:47:13
    reduce@[native code]
    global code@http://localhost:8000/test.js:44:33
    
        24
  •  11
  •   Jack G    6 年前

    下面列出了两种不同的函数声明之间的四个值得注意的比较。

    1. 功能的可用性(范围)

    以下工作是因为 function add() 范围为最近的块:

    try {
      console.log("Success: ", add(1, 1));
    } catch(e) {
      console.log("ERROR: " + e);
    }
    
    function add(a, b){
      return a + b;
    }

    以下内容不起作用(因为 var add= 超级种子 函数附加项() )

    try {
      console.log("Success: ", add(1, 1));
    } catch(e) {
      console.log("ERROR: " + e);
    }
    
    var add=function add(a, b){
      return a + b;
    }

    以下内容不起作用,因为 add 在使用后声明。

    try {
      console.log("Success: ", add(1, 1));
    } catch(e) {
      console.log("ERROR: " + e);
    }
    
    var add=function(a, b){
      return a + b;
    }
    1. (函数) 名字

    函数的名称 function thefuncname(){} 函数名 当它以这种方式声明时。

    function foobar(a, b){}
    
    console.log(foobar.name);

    var a = function foobar(){};
    
    console.log(a.name);

    否则,如果函数声明为 function(){} , the 功能 .name是用于存储函数的第一个变量。

    var a = function(){};
    var b = (function(){ return function(){} });
    
    console.log(a.name);
    console.log(b.name);

    如果没有为函数设置变量,则函数名为空字符串( "" )

    console.log((function(){}).name === "");

    最后,当分配给函数的变量最初设置名称时,设置给函数的连续变量不会更改名称。

    var a = function(){};
    var b = a;
    var c = b;
    
    console.log(a.name);
    console.log(b.name);
    console.log(c.name);
    1. 性能

    在谷歌的V8和火狐的蜘蛛猴中,可能存在几微秒的JIST编译差异,但最终结果是完全相同的。为了证明这一点,让我们通过比较两个空白代码片段的速度来检查微基准处JSPerf的效率。这个 JSPerf tests are found here . 而且, jsben.ch testsare found here . 正如你所看到的,当应该没有的时候有一个明显的区别。如果您真的像我一样是一个性能怪人,那么在尝试减少范围内的变量和函数的数量,特别是消除多态性(例如使用同一个变量存储两个不同的类型)的同时,它可能更有价值。

    1. 变量可变性

    当你使用 var 关键字声明一个变量,然后可以像这样为变量重新分配不同的值。

    (function(){
        "use strict";
        var foobar = function(){}; // initial value
        try {
            foobar = "Hello World!"; // new value
            console.log("[no error]");
        } catch(error) {
            console.log("ERROR: " + error.message);
        }
        console.log(foobar, window.foobar);
    })();

    但是,当我们使用const语句时,变量引用变得不可变。这意味着我们不能给变量赋值。但是,请注意,这不会使变量的内容不可变:如果这样做 const arr = [] ,那么你仍然可以 arr[10] = "example" . 只是做一些像 arr = "new value" arr = [] 将引发如下所示的错误。

    (function(){
        "use strict";
        const foobar = function(){}; // initial value
        try {
            foobar = "Hello World!"; // new value
            console.log("[no error]");
        } catch(error) {
            console.log("ERROR: " + error.message);
        }
        console.log(foobar, window.foobar);
    })();

    有趣的是,如果我们将变量声明为 function funcName(){} ,则变量的不可变性与用 var .

    (function(){
        "use strict";
        function foobar(){}; // initial value
        try {
            foobar = "Hello World!"; // new value
            console.log("[no error]");
        } catch(error) {
            console.log("ERROR: " + error.message);
        }
        console.log(foobar, window.foobar);
    })();

    最近的街区是什么

    “最近的块”是最近的“函数”(包括异步函数、生成器函数和异步生成器函数)。然而,有趣的是, function functionName() {} 表现得像个 var functionName = function() {} 当在一个非封闭块外的项目说封闭。观察。

    • 正常的 var add=function(){}

    try {
      // typeof will simply return "undefined" if the variable does not exist
      if (typeof add !== "undefined") {
        add(1, 1); // just to prove it
        console.log("Not a block");
      }else if(add===undefined){ // this throws an exception if add doesn't exist
        console.log('Behaves like var add=function(a,b){return a+b}');
      }
    } catch(e) {
      console.log("Is a block");
    }
    var add=function(a, b){return a + b}
    • 正常的 function add(){}

    try {
      // typeof will simply return "undefined" if the variable does not exist
      if (typeof add !== "undefined") {
        add(1, 1); // just to prove it
        console.log("Not a block");
      }else if(add===undefined){ // this throws an exception if add doesn't exist
        console.log('Behaves like var add=function(a,b){return a+b}')
      }
    } catch(e) {
      console.log("Is a block");
    }
    function add(a, b){
      return a + b;
    }
    • 功能

    try {
      // typeof will simply return "undefined" if the variable does not exist
      if (typeof add !== "undefined") {
        add(1, 1); // just to prove it
        console.log("Not a block");
      }else if(add===undefined){ // this throws an exception if add doesn't exist
        console.log('Behaves like var add=function(a,b){return a+b}')
      }
    } catch(e) {
      console.log("Is a block");
    }
    (function () {
        function add(a, b){
          return a + b;
        }
    })();
    • 声明(如 if , else , for , while , try / catch / finally , switch , do / 虽然 , with )

    try {
      // typeof will simply return "undefined" if the variable does not exist
      if (typeof add !== "undefined") {
        add(1, 1); // just to prove it
        console.log("Not a block");
      }else if(add===undefined){ // this throws an exception if add doesn't exist
        console.log('Behaves like var add=function(a,b){return a+b}')
      }
    } catch(e) {
      console.log("Is a block");
    }
    {
        function add(a, b){
          return a + b;
        }
    }
    • 箭头函数 var add=function()

    try {
      // typeof will simply return "undefined" if the variable does not exist
      if (typeof add !== "undefined") {
        add(1, 1); // just to prove it
        console.log("Not a block");
      }else if(add===undefined){ // this throws an exception if add doesn't exist
        console.log('Behaves like var add=function(a,b){return a+b}')
      }
    } catch(e) {
      console.log("Is a block");
    }
    (() => {
        var add=function(a, b){
          return a + b;
        }
    })();
    • 箭头函数 函数附加项()

    try {
      // typeof will simply return "undefined" if the variable does not exist
      if (typeof add !== "undefined") {
        add(1, 1); // just to prove it
        console.log("Not a block");
      }else if(add===undefined){ // this throws an exception if add doesn't exist
        console.log('Behaves like var add=function(a,b){return a+b}')
      }
    } catch(e) {
      console.log("Is a block");
    }
    (() => {
        function add(a, b){
          return a + b;
        }
    })();
        25
  •  10
  •   Peter Mortensen icecrime    8 年前

    在javascript中,有两种创建函数的方法:

    1. 函数声明:

      function fn(){
        console.log("Hello");
      }
      fn();
      

      这是非常基本的,不言自明的,在许多语言中使用,并且在C语言家族中使用标准。我们声明了一个定义它的函数,并通过调用它来执行它。

      您应该知道的是,函数实际上是javascript中的对象;在内部,我们为上述函数创建了一个对象,并为其命名为fn,或者对该对象的引用存储在fn中。函数是JavaScript中的对象;函数的实例实际上是一个对象实例。

    2. 函数表达式:

      var fn=function(){
        console.log("Hello");
      }
      fn();
      

      JavaScript具有一流的函数,即创建一个函数并将其分配给一个变量,就像创建一个字符串或数字并将其分配给一个变量一样。这里,fn变量被分配给一个函数。这个概念的原因是函数是javascript中的对象;fn指向上述函数的对象实例。我们已经初始化了一个函数并将它赋给了一个变量。它不会执行函数并分配结果。

    参考文献: JavaScript function declaration syntax: var fn = function() {} vs function fn() {}

        26
  •  8
  •   Peter Mortensen icecrime    9 年前

    两者都是定义函数的不同方法。不同之处在于浏览器如何解释它们并将它们加载到执行上下文中。

    第一种情况是函数表达式,它只在解释器到达该行代码时加载。因此,如果您像下面这样做,您将得到一个错误, 函数one不是函数 .

    functionOne();
    var functionOne = function() {
        // Some code
    };
    

    原因是在第一行中没有给functionone赋值,因此它是未定义的。我们试图把它称为函数,因此我们得到了一个错误。

    在第二行中,我们将一个匿名函数的引用赋给functionone。

    第二种情况是在执行任何代码之前加载的函数声明。因此,如果您这样做,那么在代码执行之前加载声明时不会得到任何错误。

    functionOne();
    function functionOne() {
       // Some code
    }
    
        27
  •  8
  •   Panos Kalatzantonakis    7 年前

    关于性能:

    新版本 V8 介绍了几种引擎盖下的优化,以及 SpiderMonkey .

    现在表达式和声明之间几乎没有区别。
    函数表达式 appears to be faster 现在。

    铬62.0.3202 Chrome test

    火狐55 Firefox test

    铬金丝雀63.0.3225 Chrome Canary test


    Anonymous 函数表达式 appear to have better performance 反对 Named 函数表达式。


    火狐 Firefox named_anonymous 铬金丝雀 Chrome canary named_anonymous Chrome named_anonymous

        28
  •  7
  •   Alireza    8 年前

    它们非常相似,但有一些小的区别,第一个是分配给匿名函数(函数声明)的变量,第二个是在javascript(匿名函数声明)中创建函数的正常方式,两者都有用法、缺点和优点:

    1。函数表达式

    var functionOne = function() {
        // Some code
    };
    

    函数表达式将函数定义为 表达式语法(通常是变量赋值)。功能 通过函数定义的表达式可以命名或匿名。功能 表达式不能以__函数_开头(因此括号 关于下面的自调用示例)。

    给一个函数分配一个变量,意味着没有提升,正如我们所知道的,javascript中的函数可以提升,意味着它们可以在声明之前被调用,而变量需要在获得对它们的访问之前被声明,所以在这种情况下,我们不能在声明之前访问函数,也可能是您编写函数的一种方式。对于返回另一个函数的函数,这种声明可能是有意义的,同样在上面的ecma6&中,您可以将其分配给一个可用于调用匿名函数的arrow函数,而且这种声明方法是在javascript中创建构造函数函数的更好方法。

    2。函数声明

    function functionTwo() {
        // Some code
    }
    

    函数声明定义的命名函数变量没有 需要变量赋值。函数声明的出现方式为 独立构造,不能嵌套在非功能块中。 将它们视为变量声明的兄弟,这很有帮助。 正如变量声明必须以__var_函数开头一样 声明必须以__函数__开头。

    这是在javascript中调用函数的正常方法,在您将其声明为在javascript中所有函数都被提升之前,可以调用该函数,但是如果您有“使用严格”,这将不会像预期的那样提升,这是调用所有行中不是大的、也不是构造函数函数的正常函数的好方法。

    此外,如果您需要更多有关Javascript中提升工作方式的信息,请访问以下链接:

    https://developer.mozilla.org/en-US/docs/Glossary/Hoisting

        29
  •  5
  •   Peter Mortensen icecrime    9 年前

    这只是两种可能的函数声明方法,第二种方法是在声明之前使用函数。

        30
  •  4
  •   SuperNova    9 年前

    new Function() 可用于在字符串中传递函数体。因此,这可以用来创建动态函数。也可以在不执行脚本的情况下传递脚本。

    var func = new Function("x", "y", "return x*y;");
    function secondFunction(){
       var result;
       result = func(10,20);
       console.log ( result );
    }
    
    secondFunction()