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

当在JavaScript中声明一个本地(内部)函数时,有两个select:

var关键字声明,赋值给variables:

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

使用function关键字声明,而不分配给variables:

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

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

哪个更好为什么

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

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

  2. 函数expression式:函数expression式将函数定义为较大expression式语法的一部分(通常是variables赋值)。 通过函数expression式定义的函数可以是匿名的或匿名的:

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

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

  3. 函数构造函数 :函数构造函数使用Function()构造函数dynamic地定义一个函数。 请注意函数体作为stringparameter passing给函数。 var innerFunction1 = new Function (arg1, arg2, ... argN, functionBody)

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

函数声明和函数expression式之间的区别是微妙的,您应该select最适合您需求的方法。

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

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

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

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

点击这里阅读函数声明与函数expression式与函数构造函数@MDN的详细比较

注意:通过将函数声明分配给var,函数声明可以很容易地变成函数expression式。

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

更多阅读:

这两个符号在function上是等同的。

你可以假设:

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

被解释为:

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

这就是为什么您不必在使用前声明(不定义!)。 您可以在定义它们之后重新分配函数,就像使用variables一样。 函数像variables一样被提升,因为它们是variables (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 

声明VS定义

声明是: var x 。 英文: “我将使用variablesx

定义是: x = 5 。 在英语中, “variablesx现在具有值5

"use strict"需要声明,并强制执行。 不需要使用之前的定义。 如果你的variables是在运行时定义的,那么你很好。

所以var x = 5 既是一个声明也是一个定义,就像function a() {}

命名函数不要覆盖现有variables时要小心:

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

皮棉工具将采取这一点。


何时使用哪种符号?

我会build议只有当你重新分配a稍后的值时使用函数expression式记法( var a = function () {} )。 然后函数expression式告诉读者a将被重新分配,这是故意的

函数expression式符号的另一个(次要)参数是像JSLint这样的Lint工具,可能需要您在使用函数之前声明(而不是定义!)函数。 如果你有一个recursion定义的函数,即。 a调用bb调用a ,你不能通过使用函数声明符号来声明一个。

编辑笔记:我已经做了一些关于命名匿名函数的修改。 在查看堆栈跟踪时,命名匿名函数可能非常有用。 指定的函数会给出更多的上下文,以免被logging为“匿名”。

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

而没有VAR的函数()在脚本块的分析时被定义。

这是唯一的主要区别..

因此,用户将决定需求的基础上,哪些使用,哪些符合要求..

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

只有两个真正的差异。

1)可读性和偏好

有些人发现比其他人更容易阅读的一种方式,他们将反过来在这种风格的基础上的公约。 遵循惯例很重要。

2) 轻微的节省空间

随着缩小与脚本的相关性越来越大,您可以看到使用第二种方法可能是有利的,因为它不需要使用var= ,这将在缩小的脚本中保存基本上不重要的4个字符的空间。


执行摘要

这一切都归结于偏好。 哪个更好? 你告诉我。 就个人而言,如果我打算用new创build一个对象,那么我将使用var ,然后我将首字母大写,比如Person。 否则,我倾向于camelCase它并省略使用var

  • 无function名称的var

    • 如果你掌握你的variables声明,尤其是声明的时候更好一些。

  • 不带var函数:

    • 意味着在当前范围的开始处有一个如此命名的variables声明,并且可以防止一些错误,
    • 但是 :以这种方式声明一个函数,如果在封闭variables被声明之前调用这个函数,那么使用声明为var的闭包variables将会失败。 所以,你必须知道你做了什么。

  • 带或不带var函数

    • 对class级申报有好处,
    • 并且为了分析原因,例如,如果函数不是匿名的,Chrome开发人员分析工具将更加明确:它们将具有明确的名称,您将知道代码的慢速部分在哪里。

  • 函数命名和var

    • 是将函数作为命名作用域的方式,而不必将声明的variables作为闭包
    • 同时保持variables声明的顺序。

本地声明应该总是使用var。

那么我会说,首先是更好的,因为它是一个本地范围内存和内存可以被清除符号没有更多的使用。

还有一个关于谷歌JavaScript风格指南的说明,说第二种forms不是标准的一部分,所以它不应该使用。

块内的函数声明

不要这样做:

if(x){function foo(){}}虽然大多数脚本引擎都支持块内的函数声明,但它不是ECMAScript的一部分(参见ECMA-262,第13和14章)。 更糟糕的实现是相互矛盾的,并与未来的EcmaScriptbuild议。 ECMAScript只允许在脚本或函数的根语句列表中使用函数声明。 而是使用一个用函数expression式初始化的variables来定义一个块内的函数:

if(x){

var foo = function(){}

}

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

同意@MarmiK。 两种方法的区别在于范围。 虽然函数声明默认分配本地作用域,但分配给variables的函数的作用域取决于variables的作用域。

 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指出的那样,使用一种types似乎没有范围上的优势。

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

这意味着,如果你的代码明天会被另外一个你不知道的人改变,那么开发人员无法find函数声明的地方,那么你必须使用函数声明(我的意思是函数x(){} ),或者如果您首先声明函数,则可以使用expression式。

我认为每个用JavaScript开始编程的人迟早会问自己的问题。 我会重新提出你的问题:

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

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

那些喜欢使用函数语句的人大多不使用它,而是需要定义只读函数variables,而不是为什么他们不想在使用它之前声明它。 在我看来,主要是因为喜欢这种forms。

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

我的第一个语言是Pascal,C,Fortran,C ++等。我现在用C#。 所以当我开始编写JavaScript程序的时候,我在开始时使用了另一种语言编写程序的现有风格 。 后来我改变了我的JavaScript代码对应于特定语言的样式。

个人更喜欢使用函数expression式,并且在外部函数的第一个语句中声明了所有的函数。 我发现这个forms大部分都是通过JavaScript语义清楚的,其中函数的名字是可变的,包含一个函数值。 函数的名字像任何其他variables一样被提升 。 例如我的代码如下所示

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

我很less使用函数语句 ,只有在声明这个类的构造函数时才会这样做:

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

我尝试不使用第三种forms:

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

myFunc2被另外声明为myFunc1 。 这种forms的实现取决于Web浏览器。 它有可能在使用recursion函数的情况下。

定义一个javascript函数

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

  1. 函数构造函数
  2. 函数声明
  3. 函数expression式

缺点函数构造函数:

函数构造函数需要函数体作为一个string:

  • 可能会阻止一些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.

函数声明的缺点:

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

  • 如果你在另一个函数里面做了一个新的函数声明,你怎么能达到你的新函数呢? 请参阅jQuery Document Ready和Function Scope
  • 为什么函数声明在被定义之前是可调用的,而其余的javascript的行为是不同的?
  • 你知道在后台“函数声明还创build了一个名称与函数名称相同的variables”!
  • 如果一个与函数声明同名的variables在之前(或之后)被定义,会发生什么?
  • 我的function定义仍然可以用一对括号括起来吗? http://jsbin.com/makipuxaje/1/edit?js,console与http://jsbin.com/demecidoqu/1/edit?js,console与http://jsbin.com/xikufakuwo/1/edit?; JS,控制台
  • 把函数声明转换成函数expression式是非常容易的,有意或无意的,你明白其后果吗? 请参阅感叹号在函数之前做了什么? 还有JavaScript加号在函数名前面
  • Javascriptfunction范围和提升
  • 为什么我的JavaScript函数名称冲突?

functionexpression的优点:

函数expression式更简单:

  • 你“知道”它分配给了什么variables
  • 你不能在其定义之前调用/引用函数分配给的variables,这与其余的javascript定义是一致的

更多关于:将函数声明转换成函数expression式

危险:正如“函数声明的缺点”中提到的,这可能导致许多问题,下面是更多的细节。

将函数声明转换为函数expression式非常简单。

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

“函数语句可能会被提起,这意味着无论函数被放置在什么地方,它都会被移动到被定义的范围的顶部,这就放松了函数应该在使用之前被声明的要求,这是我认为的它也禁止在if语句中使用函数语句,事实certificate,大多数浏览器都允许在if语句中使用函数语句,但是它们应该如何解释,从而产生了可移植性问题。 – 从书: Javascript的好部分


更多关于函数expression式

语法如下:

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

需要注意的是[name] (在语法的“function”之后):

  • function名称可以省略 ,在这种情况下,该function被称为匿名function
  • “函数名称不能改变,而函数分配的variables可以重新分配。”
  • “函数名称只能在函数体内使用”。 ,你可以使用这个特性来recursion地调用它自己。

然后使用[name]你可以做一些奇怪/有趣的事情,如下面。 请注意,如果你是新的函数定义,我不build议这样做。

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

另外要注意的是:可以立即调用函数expression式,而函数声明不能​​。 这个function在IIFE中使用,请阅读更多关于在“(function(){…})()”之类的匿名函数中封装整个Javascript文件的用途是什么?


资源

简短的回答:在代码中没有关系,但是你应该把var放在可读性上。

长答案: JavaScript中的局部variables,就像JavaScript中的全局variables一样,可以使用或不使用var来定义。 因此,程序的function不会受到var这个词的缺失或存在的干扰。 因为使用var读取代码更容易,所以build议在首次声明variables之前将var放在variables之前。 但是如果你想让它变得不可读,那么在定义一个variables之前你不应该放var