在JavaScript中定义本地函数:使用var还是不使用var?

时间:2013-05-08 11:51:37

标签: javascript function closures declaration

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

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

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

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

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

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

其中哪些更好为什么

11 个答案:

答案 0 :(得分:44)

实际上有3种声明函数的方法:

  1. Function declaration:函数声明定义了一个命名函数变量,无需变量赋值。函数声明作为独立构造出现,不能嵌套在非函数块中。例如:function innerFunction1 () { };

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

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

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

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

  4. 不建议使用第三种方法,因为将函数体作为字符串传递可能会阻止某些JS引擎优化,并且容易出错。

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

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

    1. a singleton function
    2. 确定以编程方式使用的函数(使用命名函数表达式)。
    3. 函数声明和函数表达式之间的一些区别是:

      1. 函数表达式允许您在不同的点为同一个变量分配不同的函数。
      2. 函数声明定义的函数可以在函数声明本身之前使用(或者基本上在当前作用域中的任何位置),而函数表达式定义的函数只能在定义它之后使用。
      3. Click here to read the detailed comparison of Function Declaration vs Function Expression vs Function Constructor @MDN

        注意:通过将函数声明赋值给var,可以很容易地将函数声明转换为函数表达式。

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

        更多阅读:

答案 1 :(得分:7)

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

您可以认为:

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

被解释为:

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

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


<强>声明-前使用

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,您不能使用函数声明表示法先声明一个。

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

答案 2 :(得分:4)

区别在于VAR的功能是在运行时定义的,

而没有VAR的function()在脚本块的分析时间定义。

这是唯一的主要区别..

因此,用户将决定要求的基础,使用哪种,哪种适合要求..

答案 3 :(得分:2)

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

只有两个真正的区别。

1)可读性和偏好

有些人发现一种方式比其他人更容易阅读,他们反过来会根据这种方式制定约会。遵循惯例很重要。

2)轻微节省空间

随着缩小与脚本越来越相关,你可以看到使用第二种方法可能是有利的,因为它不需要使用var=这将节省一个基本上无关紧要的缩小的脚本中有4个字符的空格。


执行摘要

这一切都取决于偏好。哪个更好?你告诉我。就个人而言,如果我打算用var创建一个对象,我会使用new,然后我会将第一个字母大写,例如Person。否则,我倾向于使用它,并省略var的使用。

答案 4 :(得分:1)

  • var没有功能名称

      如果掌握变量声明,
    • 会更好:特别是 时声明它们。


  • var命名的函数:

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


  • 使用或不使用var

    命名的函数
    • 适合课堂申报,
    • 并且对于分析原因,例如,如果函数不是匿名的,Chrome开发人员分析工具将更加明确:它们将具有明确的名称,您将知道代码的缓慢部分在哪里。


  • var

    命名的函数
    • 是将函数作为命名范围而不将声明的变量作为闭包
    • 的方法
    • 同时保持掌握变量申报单。

答案 5 :(得分:1)

本地声明应始终使用var。

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

谷歌javascript风格指南中还有一条说明,第二种形式不属于标准,因此不应使用。

  

块内的功能声明

     

不要这样做:

     

if(x){function foo(){}}虽然大多数脚本引擎都支持   块内的函数声明它不是ECMAScript的一部分(参见   ECMA-262,第13和14条)。更糟糕的实现是不一致的   相互之间以及未来的EcmaScript提案。仅限ECMAScript   允许函数声明在a的根语句列表中   脚本或功能。而是使用用Function初始化的变量   用于定义块内函数的表达式:

     

if(x){

     

var foo = function(){}

     

}

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

答案 6 :(得分: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所指出的那样,使用一种类型而不是另一种类型似乎没有范围优势。

答案 7 :(得分:0)

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

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

答案 8 :(得分:0)

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

  

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

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

喜欢使用函数语句的人主要不是在他们需要定义readonly函数变量时使用它而不是为什么他们不想在使用它之前声明它。在我看来,人们使用它主要是因为一个喜欢形式。

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

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

个人更喜欢使用函数表达式样式,并在外部函数的第一个语句中声明所有函数。我发现JavaScript语义中的形式大多是清晰的,其中函数的名称是 variable 包含一个函数值。与任何其他变量一样,函数的名称受hoisting的约束。例如,我的代码如下所示

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

其中myFunc2另外声明为myFunc1。这种形式的实现取决于Web浏览器。它可能在使用递归函数的情况下有意义。

答案 9 :(得分:0)

定义javascript函数

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

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

  4. 函数构造函数的缺点:

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

    • 可能会阻止某些JS引擎优化
    • 使语法难以理解:需要转义特殊字符&amp;其他一些疯狂,见下文

      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.

    函数声明的缺点:

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

    功能表达的优点:

    函数表达式更简单:

    • 你&#34;只知道&#34;它分配给
    • 的变量
    • 在定义之前,您无法调用/引用为其分配函数的变量,这与其他javascript定义的行为一致

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

    危险:如&#34;功能声明的缺点&#34;这可能会导致许多问题,下面是更多有关此问题的详细信息。

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

    &#34;当一个函数声明成为表达式的一部分不再是一个&#34;源元素&#34;时,函数声明就不再是一个。函数或脚本本身。 A&#34;源元素&#34;是脚本中的非嵌套语句或函数体&#34; https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Examples_2

    &#34;函数语句需要提升。这意味着无论函数放在何处,它都会移动到定义函数的作用域的顶部。这放宽了在使用之前应该声明功能的要求,我认为这会导致邋iness。它还禁止在if语句中使用函数语句。事实证明,大多数浏览器都允许if语句中的函数语句,但它们的解释方式各不相同。这就产生了可移植性问题。&#34; - 来自书:Javascript The Good Parts


    有关函数表达式的更多信息

    语法如下:

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

    关于[name]的注意事项(在&#34;函数&#34;语法之后):

    • 功能名称可以省略,在这种情况下,该功能称为匿名功能
    • &#34;函数名称无法更改,而分配函数的变量可以重新分配。&#34;
    • &#34;功能名称只能在功能体内使用。&#34; ,您可以使用此功能让函数以递归方式调用自身。

    然后使用[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

    上的实时演示

    典型的实施&amp;用法如下所示。

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

    另外需要注意的是:函数表达式可以立即调用,而函数声明则不能。此功能在IIFE中使用,请参阅What is the purpose of wrapping whole Javascript files in anonymous functions like “(function(){ … })()”?


    资源

答案 10 :(得分:-3)

简短回答:代码无关紧要,但您应该var使其更具可读性。

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