JavaScript函数顺序:为什么这很重要?

原问题:

JSHint抱怨,当我的JavaScript调用一个函数,在页面的下方定义比调用它。 但是,我的页面是一个游戏,并没有function被称为整个事情下载。 那么为什么顺序函数出现在我的代码问题中呢?

编辑:我想我可能find了答案。

http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting

我在里面呻吟。 看起来我需要花一天时间重新排列六千行代码。 JavaScript的学习曲线并不陡峭,但是非常糟糕。

编辑:也包括一些ES6声明( letconst )的概述: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet

这个奇怪的行为取决于

  1. 你如何定义function和
  2. 当你打电话给他们。

这里有一些例子。

 bar(); //This won't throw an error function bar() {} foo(); //This will throw an error var foo = function() {} ---- bar(); function bar() { foo(); //This will throw an error } var foo = function() {} ---- bar(); function bar() { foo(); //This _won't_ throw an error } function foo() {} --- function bar() { foo(); //no error } var foo = function() {} bar(); 

这是因为有一种叫做吊起的东西!

有两种方法来定义函数:函数声明和函数expression式 。 如果你写的是function name() {} ,它是一个声明 ,当你写它像var name = function() {} (或一个匿名函数分配给返回,类似的东西),这是一个函数expression式

首先,我们来看看如何处理variables:

 var foo = 42; //the interpreter turns it into this: var foo; foo = 42; 

现在,如何处理函数声明

 var foo = 42; function bar() {} //turns into var foo; //Insanity! It's now at the top function bar() {} foo = 42; 

var语句会将foo创build “抛出”到最顶层,但不会将值分配给它。 函数声明接下来是行,最后一个值被赋值给foo

那这个呢?

 bar(); var foo = 42; function bar() {} //=> var foo; function bar() {} bar(); foo = 42; 

只有foo声明才会移到最上面。 这个任务只是在打电话给bar之后才发生的。

最后,为了简洁:

 bar(); function bar() {} //turns to function bar() {} bar(); 

现在,函数expression式呢?

 var foo = function() {} foo(); //=> var foo; foo = function() {} foo(); 

就像常规variables一样,首先在范围的最高点声明 foo ,然后为它赋值。

让我们来看看为什么第二个例子会抛出一个错误。

 bar(); function bar() { foo(); } var foo = function() {} //=> var foo; function bar() { foo(); } bar(); foo = function() {} 

正如我们以前所看到的,只有foo的创build才会被提升,这个任务就出现在“原始”(未挂起的)代码中。 当bar被调用时,它是在foo被赋值之前,所以foo === undefined 。 现在在bar的函数体中,就好像你在做undefined() ,这会引发一个错误。


tl; dr如果你在所有的东西加载之前都没有调用任何东西,你应该没问题。

主要原因可能是JSLint在文件上只传递一次,所以它不知道你定义这样一个函数。

如果你使用函数语句的语法

 function foo(){ ... } 

在声明函数的地方实际上没有任何区别(它总是像声明在开始时一样)。

另一方面,如果你的函数被设置为一个常规variables

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

你必须保证你不会在初始化之前调用它(这实际上可能是一个错误的来源)。


由于重新sorting大量的代码是复杂的,可能是本身的错误的来源,我build议你search一个解决方法。 我敢肯定你可以事先告诉JSLint全局variables的名字,所以它不会抱怨未声明的东西。

对文件的开始发表评论

 /*globals foo1 foo2 foo3*/ 

或者你可以在那里使用一个文本框。 (我也认为你可以通过这个parameter passing给内部的jslint函数,如果你可以插手的话)

有太多的人推动JavaScript写法的任意规则。 大多数规则是完全垃圾。

函数提升是JavaScript中的一个特性,因为它是一个好主意。

当你有一个通常是内部函数的实用工具的内部函数时,将它添加到外部函数的开头是一种可以接受的编写代码的风格,但是它的缺点是你必须仔细阅读细节来得到什么外部function呢。

你应该坚持一个原则贯穿你的代码库,把私有函数放在你的模块或函数中。 JSHint对执行一致性很好,但是你应该绝对调整.jshintrc来适应你的需要,而不是把你的源代码调整到其他人的古怪的编码概念。

一种你可能在野外看到的编码风格,你应该避免,因为它给你没有优势,只有可能的重构痛苦:

 function bigProcess() { var step1,step2; step1(); step2(); step1 = function() {...}; step2 = function() {...}; } 

这正是要避免的吊装function。 只要学习语言,并利用其优势。