59

在 JavaScript 中声明本地(内部)函数时,有两种选择:

var关键字声明,分配给变量:

(function() {
    var innerFunction1 = function() { ... };
    innerFunction1();
}());

仅使用function关键字声明,而不分配给变量:

(function() {
    function innerFunction2() { ... };
    innerFunction2();
}());

我可以看到第二种方法的一个优点:该函数可以在调用它的代码下方声明,因此更容易将私有函数与实际执行的代码分开。

哪个更好为什么

4

11 回答 11

47

实际上有 3 种方法来声明一个函数:

  1. 函数声明:函数声明定义了一个命名函数变量,而不需要变量赋值。函数声明作为独立结构出现,不能嵌套在非功能块中。前任:function innerFunction1 () { };

  2. 函数表达式::函数表达式将函数定义为更大的表达式语法(通常是变量赋值)的一部分。通过函数表达式定义的函数可以命名或匿名:

    一个。使用匿名函数 -var innerFunction1 = function() { };

    湾。使用命名函数 -var innerFunction1 = function myInnerFunction () { };

  3. 函数构造函数:函数构造函数使用 Function() 构造函数动态定义函数。请注意,函数体作为字符串参数传递给函数。 var innerFunction1 = new Function (arg1, arg2, ... argN, functionBody)

第三种方式不推荐,因为将函数体作为字符串传递可能会妨碍一些 JS 引擎优化,并且容易出错。

函数声明和函数表达式之间的差异是微妙的,您应该选择最适合您要求的方法。

我在需要的地方使用函数表达式

  1. 单例函数,或
  2. 确定以编程方式使用哪个函数(使用命名函数表达式)。

函数声明和函数表达式之间的一些区别是:

  1. 函数表达式允许您在不同点将不同的函数分配给同一变量。
  2. 由函数声明定义的函数可以在函数声明本身之前使用(或基本上在当前范围内的任何地方),而由函数表达式定义的函数只能在定义它的点之后使用。

单击此处阅读函数声明与函数表达式与函数构造函数的详细比较@MDN

注意:通过将函数声明分配给 var,可以轻松地将函数声明转换为函数表达式。

function foo() {}
alert(foo); // alerted string contains function name "foo"
var bar = foo;
alert(bar); // alerted string still contains function name "foo"

更多阅读:

于 2013-05-14T17:38:15.260 回答
8

这两种符号在功能上是等价的。

你可以假设:

function a() {}
function b() {}

被解释为:

var a, b;
a = function a() {};
b = function b() {};

这就是为什么您不必在使用前声明(而不是定义!)。您可以在定义函数后重新分配函数,就像使用变量一样。函数像变量一样被提升,因为它们是变量(头脑=吹?好!)。


使用前声明

function a() { b(); } // using b before it's declared?
function b() {}

变成:

var a, b;
a = function a() { b(); }; // nope! b is declared, we're good
b = function b() {};

重新定义函数

function a() { alert("a"); }
a = function b() { alert("b"); }; // that's weird!

变成:

var a;
a = function a() { alert("a"); };
a = function b() { alert("b"); }; // oh, that looks normal

声明与定义

声明为:var x。用英语:“我将使用变量x

定义为:x = 5。在英语中“变量x现在有值5

使用前声明是必需的,并且在"use strict". 不需要使用前定义。如果您的变量是在运行时定义的,那么您很好。

声明和var x = 5定义也是如此,就像.function a() {}

命名函数时要小心,不要覆盖现有变量:

var a = function () { alert("a"); };
var b = function a() { alert("b"); };
a(); // prints "b"

Lint工具会对此有所了解。


何时使用哪种表示法?

我建议仅在稍后var a = function () {}重新分配 的值时才使用函数表达式表示法 ( ) 。a然后,函数表达式会向读者发出信号,表明它a会被重新分配并且是有意的

函数表达式表示法的另一个(次要)参数是像 JSLint 这样的 Lint 工具,它可能需要您在使用函数之前声明(而不是定义!)函数。如果您有具有递归定义的函数,即。a调用bb调用a,您不能使用函数声明表示法先声明一个。

编辑注释:我对命名的匿名函数做了一些修改。在查看堆栈跟踪时,命名匿名函数会很有用。命名函数将提供更多上下文,以免它被记录为“匿名”。

于 2013-05-18T02:05:01.853 回答
4

不同之处在于函数 with是在运行时VAR定义的,

而没有 VAR 的 function() 是在解析时为脚本块定义的。

这是唯一的主要区别..

因此,用户将根据要求决定使用哪个,以及哪个适合要求。

于 2013-05-17T06:32:00.223 回答
2

输出没有任何区别。两者仍然可以被调用,并且都可以通过名称访问它们的原型。

只有两个真正的区别。

1) 可读性和偏好

有些人发现一种方式比其他方式更容易阅读,他们反过来会将他们的约定建立在这种风格上。遵守约定很重要。

2)节省空间

随着缩小与脚本的相关性越来越高,您可以看到使用第二种方法可能是多么有利,因为它不需要使用var=将在您的缩小脚本中节省基本上微不足道的 4 个字符的空间。


执行摘要

这一切都归结为偏好。哪个更好?你告诉我。就个人而言,var如果我打算用它来制作一个对象,我会使用它,new然后我会将第一个字母大写,例如 Person。否则,我倾向于使用驼峰命名法并省略使用var.

于 2013-05-14T23:38:58.973 回答
1

同意@MarmiK。两种方法之间的区别也在于范围。虽然函数声明默认分配局部范围,但分配给变量的函数范围取决于变量的范围。

var a;
(function() {
    var innerFunction1 = function() { ... };//local scope
    a=innerFunction1;//assigning to a global variable
}());

可以全局访问。如果您不需要更改范围,请使用函数声明。 https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope

编辑:

var a;
(function() {
    function innerFunction1() { ... };//local scope
    a=innerFunction1;//It works too(Don't know why it should though)
}());

因此,正如@Frits 所指出的,使用一种类型似乎没有范围优势。

于 2013-05-17T08:22:20.190 回答
1
  • var没有函数名

    • 如果您掌握变量声明会更好:尤其是声明它们时。


  • 没有命名的函数var

    • 意味着在当前范围的开头有一个如此命名的变量声明,它可以防止一些错误,
    • 但是:以这种方式声明函数,var如果在声明闭包变量之前调用此函数,则使用声明的闭包变量将失败。所以,你必须知道你在做什么。


  • 有或没有命名的函数var

    • 适合类声明,
    • 例如,对于分析原因,如果函数不是匿名的,Chrome 开发分析工具将更加明确:它们将具有明确的名称,您将知道代码的慢速部分在哪里。


  • 函数命名和与var

    • 是将函数作为命名范围而不将声明的变量作为闭包的方法
    • 同时保持对变量声明顺序的掌握。
于 2013-05-12T14:22:35.533 回答
1

本地声明应始终使用 var。

好吧,我会说第一个更好,因为它是一个本地范围,并且可以在符号不再使用后清除内存。

还有一个关于 google javascript style guide 的注释说第二种形式不是标准的一部分,所以不应该使用它。

块内的函数声明

不要这样做:

if (x) { function foo() {} } 虽然大多数脚本引擎支持块内的函数声明,但它不是 ECMAScript 的一部分(参见 ECMA-262,第 13 和 14 条)。更糟糕的实现彼此不一致,也与未来的 EcmaScript 提案不一致。ECMAScript 只允许在脚本或函数的根语句列表中使用函数声明。而是使用使用函数表达式初始化的变量来定义块内的函数:

如果 (x) {

var foo = 函数() {}

}

来源http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml

于 2013-05-17T02:30:44.373 回答
0

Zakas 说:“只要你总是在使用函数之前定义它们,你就可以随意使用函数声明或函数表达式。”

这意味着,如果您的代码明天将被您不认识的另一个人更改,并且这是一个开发人员无法找到函数声明位置的大项目,您必须使用函数声明(我的意思是函数 x(){} ),或者如果您首先声明函数,则可以使用表达式。

于 2013-05-15T06:45:35.870 回答
0

我认为每个开始使用 JavaScript 编程的人迟早都会问自己这个问题。我会将您的问题重新表述为:

我应该使用(更喜欢使用)函数声明函数语句)还是函数表达式var版本)?

在大多数情况下,只需使用结构中的一个就可以编写出好的 JavaScript 代码。很明显,语义上存在一些重要差异,但我想强调,在我看来,这个问题的答案主要是关于程序风格的答案。所以我会回答,在最真实的情况下,选择是品味的问题

喜欢使用函数语句的人大多不是在他们需要定义只读函数变量时使用它,而不是为什么他们不想在使用它之前声明它。在我看来,人们之所以使用它,主要是因为人们喜欢这种形式。

所以我认为你的问题没有客观正确的答案。选择是主观的。因此,我在回答中写下我个人更喜欢哪种结构以及在哪种情况下。

我的第一门语言是 Pascal、C、Fortran、C++ 等。我现在使用 C#。因此,当我开始编写 JavaScript 程序时,我一开始就使用我现有的其他语言编写程序的风格。后来我改变了我的 JavaScript 代码的风格,对应于特定的语言。

个人更喜欢使用函数表达式风格,并且我在外层函数的第一条语句中声明了所有函数。我发现这种形式对 JavaScript 语义很清楚,其中函数的名称是变量,包含一个函数值。函数的名称会像任何其他变量一样被提升。例如我的代码如下所示

(function() {
    "use strict";
    var myFunc1 = function (x) {
            // body where I can use x and this
            alert("x=" + x + ", this.foo=" + this.foo);
        },
        localVar1 = {foo: "bar"};

    myFunc1.call(localVar1, 1);
}());

我很少使用函数语句,只有当我声明类的构造函数时:

(function() {
    "use strict";
    function MyClass(x) {
        // the code of constructor
        this.abc = x;
    }
    var myInstance = new MyClass("xyz");
    alert(myInstance.abc);
}());

我尽量不要使用第三种形式:

(function() {
    "use strict";
    var myFunc1 = function myFunc2(x) {
            ...
        };
    ...    
}());

wheremyFunc2被额外声明为myFunc1. 这种形式的实现取决于网络浏览器。它可能在使用递归函数的情况下有意义。

于 2013-05-15T13:20:22.957 回答
0

定义一个javascript函数

正如 Vega 所提到的,有 3 种定义函数的方法:

  1. 函数构造函数
  2. 函数声明
  3. 函数表达式

函数构造函数的缺点:

函数构造函数需要函数体作为字符串:

  • 可能会阻止一些 JS 引擎优化
  • 使语法难以编写:需要转义特殊字符和其他一些疯狂,见下文

    var foo = (new Function("var bar = \'FOO!\';\nreturn(function() {\n\talert(bar);\n});"))();

    foo(); // The segment "function() {\n\talert(bar);\n}" of the function body string is not re-parsed.

函数声明的缺点:

它可以在函数声明本身之前调用,这实际上引入了复杂性:

函数表达式的优点:

函数表达式更简单:

  • 你“只知道”它分配给什么变量
  • 您不能在定义之前调用/引用函数分配给的变量,这与其他 javascript 定义的行为一致

更多关于:将函数声明转换为函数表达式

危险:正如“函数声明的缺点”中所述,这可能会导致许多问题,下面是有关此的更多详细信息。

将函数声明转换为函数表达式非常容易。

“函数声明在以下情况下不再是一个:成为表达式的一部分不再是函数或脚本本身的“源元素”。“源元素”是脚本或函数中的非嵌套语句正文” https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Examples_2

“函数语句会被提升。这意味着无论函数放置在哪里,它都会被移动到定义它的范围的顶部。这放宽了函数应该在使用之前声明的要求,我认为这会导致“马虎。它还禁止在 if 语句中使用函数语句。事实证明,大多数浏览器允许在 if 语句中使用函数语句,但它们的解释方式各不相同。这会产生可移植性问题。” - 来自书中:Javascript The Good Parts


更多关于函数表达式

语法如下:

 var varName = function [name]([param] [, param] [..., param]) {    /* function expression */
      statements
 }

需要注意的事项[name](就在语法中的“函数”之后):

  • 函数名可以省略,在这种情况下,该函数称为匿名函数
  • “函数名称不能更改,而函数分配给的变量可以重新分配。”
  • “函数名只能在函数体内使用。” ,您可以使用此功能让函数递归调用自身。

然后使用[name]你可以做一些奇怪/有趣的事情,如下所示。请注意,如果您不熟悉函数定义,我不建议您这样做。

var count = 0;

var varName = function funcName() {    /* function expression */
  console.log('count is: ' + count );
  if(count<1){
    count++;
    funcName();   /* calls function funcName another time  */
  }
};

varName();    // invokes function funcName via variable varName
funcName();   // throws an error as funcName is not reachable

在jsbin.com/gijamepesu/1/edit?js,console上查看现场演示

典型的实现和用法如下所示。

 var myCoolFunc = function ( username, firstName, lastName ) {    /* function expression */
      console.log('user ' + username + ' has the real full name ' + firstName + ' ' + lastName);
 }

 myCoolFunc();

还有一点需要注意:函数表达式可以立即调用,而函数声明则不能。此功能在 IIFE 中使用,请阅读更多关于将整个 Javascript 文件包装在像“(function(){ ... })()”这样的匿名函数中的目的是什么?


资源

于 2014-11-05T16:50:16.340 回答
-3

简短的回答:在代码中并不重要,但你应该var让它更具可读性。

长答案: JavaScript 中的局部变量,就像 JavaScript 中的全局变量一样,可以使用或不使用var. 因此,程序的功能不会因缺少或存在单词而受到干扰var。由于使用 更容易阅读代码var,因此建议您var在首次声明变量时将其放在变量之前。但是如果你想让它不可读,那么你不应该把它放在var定义变量之前。

于 2013-05-12T13:47:16.263 回答