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

Chr*_*thy 101 javascript function jslint jshint

原始问题:

当我的JavaScript调用一个在页面下面定义的函数而不是调用它时,JSHint会抱怨.但是,我的页面用于游戏,并且在整个内容下载之前不会调用任何函数.那么为什么订单功能出现在我的代码中呢?

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

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

我在里面呻吟.看起来我需要花一天时间重新订购六千行代码.使用javascript的学习曲线根本不是很陡峭,但它非常loooooong.

Zir*_*rak 279

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


编辑:有关一些ES6声明(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() {}
Run Code Online (Sandbox Code Playgroud)
bar();
function bar() {
    foo(); //This will throw an error
}
var foo = function() {}
Run Code Online (Sandbox Code Playgroud)
bar();
function bar() {
    foo(); //This _won't_ throw an error
}
function foo() {}
Run Code Online (Sandbox Code Playgroud)
function bar() {
    foo(); //no error
}
var foo = function() {}
bar();
Run Code Online (Sandbox Code Playgroud)

这是因为所谓的吊装!

定义函数有两种方法:函数声明和函数表达式.差别很烦人,所以我只是说这个稍微错误的东西:如果你正在写它function name() {},它就是一个声明,当你把它写成var name = function() {}(或者一个匿名函数分配给一个返回的东西,就像那样),它就是一个函数表达式.

首先,让我们看一下变量的处理方式:

var foo = 42;

//the interpreter turns it into this:
var foo;
foo = 42;
Run Code Online (Sandbox Code Playgroud)

现在,如何处理函数声明:

var foo = 42;
function bar() {}

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

var声明"抛出"的创作foo,以最顶端,但并不值分配给它.函数声明接下来排成一行,最后分配一个值foo.

那怎么样?

bar();
var foo = 42;
function bar() {}
//=>
var foo;
function bar() {}
bar();
foo = 42;
Run Code Online (Sandbox Code Playgroud)

只有声明foo移动到顶部.只有在bar完成所有提升之前的调用之后才会进行分配.

最后,为了简洁:

bar();
function bar() {}
//turns to
function bar() {}
bar();
Run Code Online (Sandbox Code Playgroud)

现在,函数表达式呢?

var foo = function() {}
foo();
//=>
var foo;
foo = function() {}
foo();
Run Code Online (Sandbox Code Playgroud)

就像普通的变量,首先foo宣布在该范围内的最高点,然后将它分配一个值.

让我们看看第二个例子抛出错误的原因.

bar();
function bar() {
    foo();
}
var foo = function() {}
//=>
var foo;
function bar() {
    foo();
}
bar();
foo = function() {}
Run Code Online (Sandbox Code Playgroud)

正如我们之前看到的那样,只有创建foo被提升,分配才出现在"原始"(未提升)代码中.当bar被调用时,它被foo赋予一个值,所以foo === undefined.现在在函数体中bar,就像你正在做的那样undefined(),它会抛出一个错误.


hug*_*omg 6

主要原因可能是JSLint只对文件进行了一次传递,因此它不知道您定义这样的函数.

如果使用函数语句语法

function foo(){ ... }
Run Code Online (Sandbox Code Playgroud)

实际上,在声明函数的地方没有任何区别(它总是表现为声明在开头).

另一方面,如果您的函数设置为常规变量

var foo = function() { ... };
Run Code Online (Sandbox Code Playgroud)

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


由于重新排序大量代码很复杂并且本身可能是错误的来源,我建议您搜索一个解决方法.我很确定你可以事先告诉JSLint全局变量的名称,所以它不会抱怨未声明的东西.

对文件的开头发表评论

/*globals foo1 foo2 foo3*/
Run Code Online (Sandbox Code Playgroud)

或者您可以在那里使用文本框.(我也认为你可以在内部jslint函数的参数中传递它,如果你可以插入它.)


Hen*_*lbo 6

有太多人对 JavaScript 的编写方式提出武断的规则。大多数规则都是垃圾。

函数提升是 JavaScript 中的一项功能,因为它是一个好主意。

当您有一个内部函数(通常是内部函数的实用程序)时,将其添加到外部函数的开头是一种可接受的代码编写风格,但它确实有一个缺点,即您必须通读详细信息才能了解内容外部函数可以。

您应该在整个代码库中坚持一个原则,要么将私有函数放在模块或函数的前面或最后。JSHint 对于强制一致性很有用,但您绝对应该调整 .jshintrc 以满足您的需求,而不是根据其他人古怪的编码概念调整您的源代码。

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

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

    step1 = function() {...};
    step2 = function() {...};
}
Run Code Online (Sandbox Code Playgroud)

这正是函数提升要避免的。只需学习该语言并利用其优势即可。