JavaScript function order: why does it matter?

原始问题:

当我的 JavaScript 调用一个函数时,JSHint 会发出抱怨,这个函数是在页面下面定义的,而不是调用它。但是,我的页面是用于一个游戏的,在整个游戏下载完成之前不会调用任何函数。那么为什么订单函数出现在我的代码中很重要呢?

编辑: 我想我可能找到了答案。

Http://www.adequatelygood.com/2010/2/javascript-scoping-and-hoisting

我在心里呻吟。看来我得再花一天时间重新订购六千行代码。Javascript 的学习曲线一点也不陡峭,但是非常漫长。

68176 次浏览

如果在加载所有内容之前不调用任何内容,那么应该没有问题。


Edit: For an overview which also covers some ES6 declarations (let, const): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet

这种奇怪的行为取决于

  1. 如何定义函数和
  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();

这是因为一种叫做 hoisting的东西!

定义函数有两种方法: 函数 声明和函数 expression。这种差别很烦人,而且很细微,所以我们只说这个稍微有点错误的事情: 如果你像 function name() {}那样写它,它就是 声明; 如果你像 var name = function() {}那样写它(或者像这样写一个赋给返回值的匿名函数) ,它就是一个函数 表情

首先,让我们看看如何处理变量:

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创造到最顶端,但是还没有给它赋值。函数声明在下一行,最后一个值被赋给 foo

And what about this?

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

只有 foo声明被移动到顶部。只有在对 bar进行调用之后,才会进行分配,而在所有提升发生之前,该分配都是在这个位置进行的。

最后,简明扼要:

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

那么,函数 表情呢?

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

Just like regular variables, first foo is declared at the highest point of the scope, then it is assigned a value.

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

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

正如我们以前看到的,只有 foo的创建被悬挂,赋值出现在“原始”(未悬挂)代码中。当调用 bar时,它是在 foo被赋值之前,因此 foo === undefined。现在在 bar的函数体中,就好像在执行 undefined()一样,它会抛出一个错误。

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

如果使用函数语句语法

function foo(){ ... }

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

On the other hand, if your function was set like a regular variable

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

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


因为重新排序大量的代码是很复杂的,而且可能本身就是 bug 的来源,所以我建议您寻找一种变通方法。我确信您可以事先告诉 JSLint 全局变量的名称,这样它就不会抱怨未声明的内容。

Put a comment on the beggining of the file

/*globals foo1 foo2 foo3*/

或者你可以用那里的文本框。(我还认为,如果可以干预的话,可以在参数中将其传递给内部的 jslint 函数。)

有太多的人推行关于如何编写 JavaScript 的武断规则,大多数规则都是垃圾。

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

当你有一个内部函数,它通常是内部函数的实用程序,将它添加到外部函数的开头是一种可以接受的编写代码的风格,但它的缺点是,你必须通过阅读细节来了解外部函数的功能。

You should stick to one principle throughout your codebase either put private functions first or last in your module or function. JSHint is good for enforcing consistency, but you should ABSOLUTELY adjust the .jshintrc to fit your needs, NOT adjust your source code to other peoples wacky coding concepts.

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

function bigProcess() {
var step1,step2;
step1();
step2();


step1 = function() {...};
step2 = function() {...};
}

这正是功能提升需要避免的。只要学习语言并发挥它的优势。

只悬挂函数声明,而不悬挂函数表达式(赋值)。