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

时间:2011-09-30 10:45:44

标签: javascript function jslint jshint

原始问题:

当我的JavaScript调用一个在页面下方定义的函数而不是调用它时,

JSHint会抱怨。但是,我的页面用于游戏,并且在整个内容下载之前不会调用任何函数。那么为什么订单函数出现在我的代码中呢?

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

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

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

4 个答案:

答案 0 :(得分:272)

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


编辑:有关概述,其中也涵盖了一些ES6声明(letconst):https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet

这种奇怪的行为取决于

  1. 如何定义功能和
  2. 当你打电话给他们时。
  3. 以下是一些例子。

    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() {},那就是声明,当你把它写成{{1}时(或分配给返回的匿名函数,类似的东西),它是一个函数表达式

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

    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,这会引发错误。

答案 1 :(得分:6)

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

如果使用函数语句语法

function foo(){ ... }

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

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

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

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


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

对文件的开头发表评论

/*globals foo1 foo2 foo3*/

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

答案 2 :(得分:3)

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

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

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

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

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

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

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

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

答案 3 :(得分:1)

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