118

原始问题:

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

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

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

我在里面呻吟。看起来我需要再花一天时间重新订购六千行代码。使用 javascript 的学习曲线一点也不陡峭,但非常漫长。

4

4 回答 4

310

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


编辑:对于还涵盖一些 ES6 声明(letconst)的概述: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();

这是因为所谓的提升

定义函数有两种方式:函数声明和函数表达式。区别是烦人的和微小的,所以让我们说这个有点错误的事情:如果你写成这样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“抛出”到最顶层,但尚未为其分配值。函数声明紧随其后,最后将一个值分配给。foofoo

那这个呢?

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

只有声明foo移到顶部。分配仅在调用 to 之后bar发生,在所有提升发生之前。

最后,为了简洁:

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

现在,函数表达式呢?

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

就像常规变量一样,首先在作用域的最高foo声明,然后分配一个值。

让我们看看为什么第二个示例会引发错误。

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

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

于 2011-09-30T13:13:39.327 回答
7

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

如果您使用函数语句语法

function foo(){ ... }

实际上,在哪里声明函数并没有什么区别(它的行为总是就像声明在开头一样)。

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

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

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


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

在文件的开头发表评论

/*globals foo1 foo2 foo3*/

或者,您可以在此处使用文本框。(我也认为你可以在参数中将它传递给内部 jslint 函数,如果你可以干预它。)

于 2011-09-30T13:14:15.940 回答
4

有太多人在推动关于如何编写 JavaScript 的任意规则。大多数规则都是垃圾。

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

当你有一个内部函数通常是内部函数的实用程序时,将它添加到外部函数的开头是一种可接受的代码编写方式,但它确实有一个缺点,你必须通读细节才能得到什么外部函数可以。

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

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

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

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

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

于 2015-04-18T14:10:30.017 回答
2

只有函数声明被提升而不是函数表达式(赋值)。

于 2017-12-13T05:46:38.080 回答