var functionName = function(){}与function functionName(){}

2020/09/13 15:06 · javascript ·  · 0评论

我最近开始维护别人的JavaScript代码。我正在修复错误,添加功能,还试图整理代码并使之更加一致。

以前的开发人员使用了两种方法来声明函数,无论是否有原因,我都无法弄清楚。

两种方式是:

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

使用这两种不同方法的原因是什么,每种方法的利弊是什么?有什么方法可以用一种方法不能完成的吗?

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

例如,一个函数表达式:

// TypeError: functionOne is not a function
functionOne();

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

并且,一个函数声明:

// Outputs: "Hello!"
functionTwo();

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

从历史上看,在块内定义的函数声明在浏览器之间不一致地处理。严格模式(在ES5中引入)通过将函数声明的作用域限定在其封闭块中来解决。

'use strict';    
{ // note this block!
  function functionThree() {
    console.log("Hello!");
  }
}
functionThree(); // ReferenceError

首先,我想更正Greg: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"

使用组合样式的一个令人信服的原因是函数对象的“名称”属性(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(){};

取决于上下文,并且可能让您猜测它的实际定义位置,尤其是在以下情况下eval()-答案是:它取决于浏览器。

以下是创建函数的标准表单的摘要:(本来是为另一个问题而写的,但在移入规范问题后进行了修改。)

条款:

快速清单:

  • 功能声明

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

  • 命名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,该规范并没有涵盖,如果你把一个函数声明等的控制结构内部的JavaScript引擎应该做的事情tryifswitchwhile,等等,是这样的:

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

而且由于它们是运行分步代码之前进行处理的,因此要知道它们在控制结构中时该怎么做是很棘手的。

尽管直到ES2015 指定执行此操作,但这是允许的扩展,以支持块中的函数声明。不幸的是(不可避免),不同的引擎做了不同的事情。

从ES2015开始,该规范说明了怎么做。实际上,它提供了三项独立的操作:

  1. 如果松散模式不是在Web浏览器,JavaScript引擎是应该做的一件事
  2. 如果在网络浏览器上处于松散模式,则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)

“匿名” function表达

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

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

像所有表达式一样,在逐步执行代码时会对其进行评估。

在ES5中,此函数创建的函数没有名称(匿名)。在ES2015中,如果可能,可以通过从上下文推断函数来为其分配名称。在上面的示例中,名称为y当函数是属性初始值设定项的值时,将执行类似的操作。(有关何时发生这种情况的细节和规则,搜索SetFunctionName规范  -它似乎遍布的地方。)

命名function表达

第三种形式是命名函数表达式(“ 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 ,从而在两个不同的时间创建了两个不同的功能。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.definePropertyObject.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()通话中了吗?这是一个功能。

关于箭头功能的几件事:

  1. 他们没有自己的this相反,他们关闭了this他们定义成背景。(它们也会关闭,arguments并在相关时显示super。)这意味着this它们中的内容与this创建位置相同,并且无法更改。

  2. 正如您在上述内容中已经注意到的那样,您无需使用关键字function;。而是使用=>

n => 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将条目作为第一个参数传递,将索引作为第二个参数传递。)

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

如果要执行的任务不只是单个表达式,请照常使用{}和显式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));

不带版本的版本{ ... }称为带有表达式主体简洁主体的箭头函数(也:简洁的箭头函数。){ ... }定义主体的函数是带有函数body的箭头函数(还:详细的箭头功能。)

对象初始化器中的方法声明(ES2015 +)

ES2015允许使用一种简短形式来声明引用一个称为方法定义的函数的属性它看起来像这样:

var o = {
    foo() {
    }
};

ES5和更早版本中几乎相等的是:

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

区别(除了冗长)是方法可以使用super,但函数不能使用。因此,例如,如果您有一个valueOf使用方法语法定义(例如)的对象,则该对象可以super.valueOf()用来获取Object.prototype.valueOf将返回的值(大概在使用它进行其他操作之前),而ES5版本则必须这样做Object.prototype.valueOf.call(this)

这也意味着该方法具有对其定义对象的引用,因此,如果该对象是临时的(例如,您将其Object.assign作为源对象之一传递给它),则方法语法可能意味着该对象已保留。否则可能会被垃圾回收(如果JavaScript引擎未检测到这种情况并在没有方法使用的情况下进行处理super)。

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

ES2015为我们带来了class语法,包括声明的构造函数和方法:

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    getFullName() {
        return this.firstName + " " + this.lastName;
    }
}

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

说到全局上下文,var语句和FunctionDeclaration末尾的a都会在全局对象上创建一个不可删除的属性,但是两者的值都可以被覆盖

两种方式之间的细微差别是,当变量实例化过程运行时(在实际代码执行之前),所有用声明的标识符var将用初始化undefinedFunctionDeclaration从那时起,使用的标识符将可用,例如:

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

分配bar FunctionExpression一直进行到运行时。

由a创建的全局属性FunctionDeclaration可以被覆盖而没有任何问题,就像变量值一样,例如:

 function test () {}
 test = null;

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

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

在没有var语句的情况下进行赋值,如果在范围链中找不到引用的标识符,它将成为全局对象可删除属性。

另外,未声明的分配ReferenceError严格模式下在ECMAScript 5上抛出

必须阅读:

注意:此答案已与另一个问题合并,其中来自OP的主要疑问和误解是,用a声明的标识符FunctionDeclaration不能被覆盖,事实并非如此。

您在此处张贴的两个代码段几乎可以出于所有目的以相同的方式运行。

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

使用第二个变体(function functionTwo()),该函数可用于在声明该函数的位置之上运行的代码。

这是因为对于第一个变量,foo在运行时会将函数分配给变量在第二步中,foo在解析时将功能分配给该标识符

更多技术信息

JavaScript具有三种定义函数的方式。

  1. 您的第一个代码片段显示了一个函数表达式这涉及到使用“函数”运算符来创建函数-该运算符的结果可以存储在任何变量或对象属性中。这样函数表达式功能强大。函数表达式通常称为“匿名函数”,因为它不必具有名称,
  2. 您的第二个示例是函数声明这使用“功能”语句创建功能。该函数在解析时可用,并且可以在该范围内的任何位置调用。以后您仍然可以将其存储在变量或对象属性中。
  3. 定义函数的第三种方法是“ Function()”构造函数,该函数未在原始文章中显示。不建议使用此功能,因为它的工作方式与相同eval(),但存在问题。

格雷格答案的更好解释

functionTwo();
function functionTwo() {
}

为什么没有错误?我们总是被教导表达式从上到下执行(??)

因为:

hoistedJavaScript解释器总是将函数声明和变量声明不可见地移动()到其包含范围的顶部。函数参数和语言定义的名称显然已经存在。本樱桃

这意味着这样的代码:

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

请注意,声明的赋值部分未悬挂。仅悬挂名称。

但是对于函数声明,整个函数体也将被提升

functionTwo();              ---------------      function functionTwo() {
                            | is actually |      };
function functionTwo() {    | interpreted |-->
}                           |    like     |      functionTwo();
                            ---------------

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

我经常用以下模式构建JavaScript模块:

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

    exports.publicUtil = function() {
            ...
    };

    return exports;
})();

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

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

当您需要避免覆盖函数的先前定义时,最好使用第一种方法而不是第二种方法。

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

,此定义myfunction将覆盖任何先前的定义,因为它将在解析时完成。

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

做正确的工作,myfunction定义何时condition满足。

一个重要的原因是添加一个且仅一个变量作为名称空间的“根”。

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

}

要么

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

有很多命名空间的技术。可用的JavaScript模块数量越来越多,这一点变得越来越重要。

另请参阅如何在JavaScript中声明名称空间?

提升 是JavaScript解释器将所有变量和函数声明移至当前作用域顶部的动作。

但是,仅悬挂实际的声明。通过将作业留在原处。

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

变量

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 ”,变量声明的默认值也为“ undefined”

    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构造函数类:使用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引入了Arrow函数Arrow函数表达式具有较短的语法,它们最适合于非方法函数,并且不能用作构造函数。

ArrowFunction : ArrowParameters => ConciseBody

const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; };
console.log( fn(2) ); // Even
console.log( fn(3) ); // Odd

我添加自己的答案只是因为其他所有人都已经完全涵盖了吊装部分。

我想知道很长一段时间以来哪种方法更好,并且由于现在知道http://jsperf.com,我知道:)

在此处输入图片说明

函数声明更快,这就是Web开发人员真正重要的事情吧?;)

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

但是,在功能对象实际与其变量相关联的方式时间上存在差异这种差异是由于JavaScript中称为变量提升的机制引起的

基本上,所有函数声明和变量声明都被提升到声明所在函数的顶部(这就是我们说JavaScript具有函数作用域的原因)。

  • 吊起函数声明时,函数主体将“跟随”,因此在评估函数主体时,变量将立即绑定到函数对象。

  • 当一个变量声明悬挂,初始化并没有
    跟随,而是“留下”。
    将该变量初始化为
    undefined函数体的开头,并将
    在代码的原始位置为其
    分配一个值。(实际上,将在每个声明具有相同名称的变量的每个位置分配一个值。)

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

一些例子...

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

变量foo被提升到的功能,初始化的顶部undefined,从而使!footrue,所以foo被分配10范围foo外部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

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

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

这里首先悬挂函数声明,然后声明和初始化变量a接下来,分配此变量10换句话说:分配没有分配给外部变量a

第一个示例是函数声明:

function abc(){}

第二个示例是一个函数表达式:

var abc = function() {};

主要区别在于如何吊起(吊起和声明)它们。在第一个示例中,整个函数声明被提升。在第二个示例中,仅吊起var'abc',其值(函数)将未定义,并且函数本身保持在声明的位置。

简而言之:

//this will work
abc(param);
function abc(){}

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

要研究有关此主题的更多信息,强烈建议您使用此
链接

就代码维护成本而言,更可取的是命名函数:

  • 与声明它们的位置无关(但仍然受范围限制)。
  • 更能抵抗诸如条件初始化之类的错误(如果需要,您仍然可以覆盖)。
  • 通过与作用域功能分开分配局部功能,代码变得更具可读性。通常在范围内,功能优先,然后是局部功能的声明。
  • 在调试器中,您将清楚地在调用堆栈上看到函数名称,而不是“匿名/求值”函数。

我怀疑后面还会有更多针对命名函数的PROS。命名函数的优点被列为匿名函数的缺点。

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

{
    member:function() { /* How do I make "this.member" a named function? */
    }
}

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

有关匿名函数和lambda演算的更多信息,Wikipedia是一个好的开始(http://en.wikipedia.org/wiki/Anonymous_function)。

我在代码中使用可变方法的原因非常特殊,上面已以抽象的方式介绍了其理论,但示例可能会帮助像我这样的人,但是他们的JavaScript专业知识有限。

我有需要与160个独立设计的品牌一起运行的代码。大多数代码位于共享文件中,而与品牌有关的内容位于单独的文件中,每个品牌一个。

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

通过使用变量语法,我可以在共享代码中声明变量(本质上是一个函数指针),然后分配一个琐碎的桩函数,或者设置为null。

然后,需要该功能的特定实现的一个或两个品牌可以定义其功能版本,然后根据需要将其分配给变量,其余的则不执行任何操作。我可以在共享代码中执行null函数之前对其进行测试。

从上面的人们的评论中,我认为也许也可以重新定义静态函数,但是我认为变量解决方案很好而且很明确。

Greg的Answer足够好,但是我仍然想在我刚刚看过Douglas Crockford的视频时学到一些东西

函数表达式:

var foo = function foo() {};

功能说明:

function foo() {};

函数语句只是var带有function值的语句的简写形式

所以

function foo() {};

扩展到

var foo = function foo() {};

进一步扩展为:

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

而且它们都被提升到了代码的顶部。

视频截图

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

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

以下工作是由于function add()范围最接近的块:

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

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;
}

上面的代码在功能上与下面的代码相同。请注意,显式分配add = undefined是多余的,因为简单地做var add;与完全相同var add=undefined

var add = undefined;

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

add = function(a, b){
  return a + b;
}

以下内容无效,因为已var add=取代function add()

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

var add=function add(a, b){
  return a + b;
}
  1. (功能) .name

一个函数的名称function thefuncname(){}thefuncname当它这样声明。

function foobar(a, b){}

console.log(foobar.name);

var a = function foobar(){};

console.log(a.name);

否则,如果将一个函数声明为function(){},则函数 .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. 性能

在Google的V8和Firefox的Spidermonkey中,可能会有几微秒的JIST编译差异,但最终结果是完全相同的。为了证明这一点,让我们通过比较两个空白代码段的速度来检验JSPerf在微基准测试中的效率。此可以找到JSPerf测试并且,jsben.ch测试位于此处如您所见,什么都不应该有明显的区别。如果您确实是像我这样的性能狂,那么尝试减少范围中的变量和函数的数量,尤其是消除多态性(例如使用相同的变量存储两种不同的类型)可能更值得。

  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);
})();

什么是“最近的街区”

“最近的块”是最接近的“函数”(包括异步函数,生成器函数和异步生成器函数)。但是,有趣的是,a的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;
    }
})();
  • 言(例如ifelseforwhiletry/ catch/ finallyswitchdo/ whilewith
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;
    }
})();
  • 箭头功能 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;
    }
})();

@EugeneLazutkin给出了一个示例,其中他命名了一个分配的函数,该函数可以shortcut()用作对其自身的内部引用。John Resig给出了另一个示例- 在他的Learning Advanced Javascript教程中复制分配给另一个对象的递归函数虽然在这里分配功能并不是严格意义上的问题,但我还是建议您积极尝试本教程-单击右上角的按钮运行代码,然后双击该代码进行编辑。

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

删除原始忍者对象后,测试将失败。(第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?" ); 
}

如果您命名将被递归调用的函数,则测试将通过。(第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." );

其他答案中未提及的另一个区别是,如果您使用匿名函数

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

第一个(函数doSomething(x))应该是对象表示法的一部分。

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

您可能想知道什么是函数声明函数表达式

函数声明定义了一个命名函数变量,而无需分配变量。函数声明作为独立的构造出现,并且不能嵌套在非函数块中。

function foo() {
    return 3;
}

ECMA 5(13.0)将语法定义为

函数标识符(FormalParameterList
opt){FunctionBody}

在上述条件下,函数名称在其范围和其父级范围内可见(否则它将无法访问)。

并在函数表达式中

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

// 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)将语法定义为

函数标识符
opt(FormalParameterList opt){FunctionBody}

我列出了以下差异:

  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()}

如果使用这些函数创建对象,则会得到:

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

根据“命名函数显示在堆栈跟踪中”的说法,现代JavaScript引擎实际上具有表示匿名函数的能力。

在撰写本文时,V8,SpiderMonkey,Chakra和Nitro始终通过名称来引用命名函数。如果有匿名函数,它们几乎总是通过其标识符来引用它。

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

如果您确实真的希望您的迭代器和成功回调出现在跟踪中,那么您也可以为其命名...

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

但在大多数情况下,不值得强调。

线束(小提琴

'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

在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函数声明语法:var fn = function(){} vs function fn(){}

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

第一种情况是函数表达式,仅在解释器到达该行代码时才加载。因此,如果按照以下方式进行操作,则会收到错误消息,提示functionOne不是function

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

原因是第一行没有将任何值分配给functionOne,因此未定义。我们试图将其称为函数,因此会出现错误。

在第二行中,我们将匿名函数的引用分配给functionOne。

第二种情况是在执行任何代码之前加载的函数声明。因此,如果您喜欢以下内容,则在代码执行之前加载声明不会有任何错误。

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

关于效果:

新版本V8引入了多项后台优化,因此也进行了优化SpiderMonkey

现在,表达式和声明之间几乎没有区别。现在
函数表达似乎更快

铬62.0.3202
镀铬测试

火狐55
Firefox测试

铬金丝雀63.0.3225
Chrome Canary测试

Anonymous函数表达式似乎
Named函数表达式具有更好的性能

Firefox
浏览器Canary ChromeFirefox named_anonymous

Chrome金丝雀named_anonymous

Chrome named_anonymous

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

1.函数表达式

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

函数表达式将函数定义为更大的表达式语法(通常是变量赋值)的一部分。通过函数表达式定义的函数可以命名或匿名。函数表达式不能以“函数”开头(因此,下面的自调用示例周围带有括号)。

为函数分配变量意味着没有提升,因为我们知道JavaScript中的函数可以提升,意味着可以在声明它们之前调用它们,而在访问它们之前需要先声明变量,因此在这种情况下,我们不能在声明函数之前访问函数,这也可能是您编写函数的一种方式,对于返回另一个函数的函数,这种声明很有意义,同样在ECMA6及以上版本中,您可以将其分配给箭头函数,可以用来调用匿名函数,这种声明方式也是在JavaScript中创建构造函数的更好方法。

2.功能声明

function functionTwo() {
    // Some code
}

函数声明定义了一个命名函数变量,而无需分配变量。函数声明作为独立的构造出现,不能嵌套在非函数块中。将它们视为变量声明的兄弟是有帮助的。就像变量声明必须以“ var”开始一样,函数声明也必须以“ function”开始。

这是在JavaScript中调用函数的通常方式,可以在您甚至声明它之前就调用该函数,因为在JavaScript中所有函数都被提升了,但是如果您“严格使用”这将无法按预期进行提升,那么这是一个好方法调用所有行数不大且都不是构造函数的普通函数。

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

https://developer.mozilla.org/zh-CN/docs/Glossary/Hoisting

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

new Function()可用于以字符串形式传递函数的主体。因此,可以将其用于创建动态功能。也传递脚本而不执行脚本。

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

secondFunction()
本文地址:http://javascript.askforanswer.com/var-functionname-functionyufunction-functionname.html
文章标签: ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!