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


106

原始问题:

当我的JavaScript调用的功能在页面下方而不是对其进行调用时,JSHint会抱怨。但是,我的页面是用于游戏的,在下载完所有内容之前,不会调用任何函数。那么为什么订单功能出现在我的代码中很重要?

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

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

我在里面吟。看来我需要花另一天的时间才能重新排序六千行代码。使用javascript的学习曲线一点也不陡峭,但是非常糟糕。


+1是更新中的出色参考。我希望这使您确信,您确实不需要重新排序代码。:)
2011年

Answers:


294

tl; dr如果不加载任何东西,直到一切加载完毕,就可以了。


编辑:有关还涵盖一些ES6声明()的概述let,请访问consthttps : //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声明“抛出”的创作foo,以最顶端,但并不值分配给它。函数声明排在第二行,最后将值分配给foo

那呢?

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();

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

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

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

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


抱歉,对此进行了总结,但是是否出现了诸如Array.prototype.someMethod = function(){}的重载?如果这些类型的内容位于脚本的结尾,我似乎会出错。
边缘

您如何确保一切正常?有什么惯例吗?
zwcloud '18

6

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

如果使用函数语句语法

function foo(){ ... }

实际上,您在声明函数的位置根本没有区别(它的行为始终就像声明是在开头一样)。

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

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

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


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

在文件的开头添加评论

/*globals foo1 foo2 foo3*/

或者,您可以在此处使用文本框。(我还认为,如果您可以将其传递给内部jslint函数,则可以将其传递给内部jslint函数。)


谢谢。那么/ * globals * /行会起作用吗?很好-让JsHint喜欢我的一切。我仍然不熟悉JavaScript,并在刷新页面时出现莫名其妙的暂停,但是没有报告的错误。因此,我认为解决方案是遵循所有规则,然后查看它是否仍会发生。
克里斯·托尔沃西

4

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

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

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

在整个代码库中,您应该坚持一个原则,即在模块或函数中将私有函数放在首位或最后。JSHint可以很好地增强一致性,但是您应该绝对地调整.jshintrc以适合您的需求,而不是针对其他古怪的编码概念来调整源代码。

您应该避免在野外看到的一种编码样式,因为它没有任何好处,只会给您带来重构的痛苦:

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

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

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


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.