JavaScript函数顺序:为什么这很重要?
原问题:
JSHint抱怨,当我的JavaScript调用一个函数,在页面的下方定义比调用它。 但是,我的页面是一个游戏,并没有function被称为整个事情下载。 那么为什么顺序函数出现在我的代码问题中呢?
编辑:我想我可能find了答案。
http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting
我在里面呻吟。 看起来我需要花一天时间重新排列六千行代码。 JavaScript的学习曲线并不陡峭,但是非常糟糕。
编辑:也包括一些ES6声明( let
, const
)的概述: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet
这个奇怪的行为取决于
- 你如何定义function和
- 当你打电话给他们。
这里有一些例子。
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。 只要学习语言,并利用其优势。