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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7609276/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 02:53:35  来源:igfitidea点击:

JavaScript function order: why does it matter?

javascriptfunctionjslintjshint

提问by Chris Tolworthy

Original Question:

原问题:

JSHintcomplains when my JavaScript calls a function that is defined further down the page than the call to it. However, my page is for a game, and no functions are called until the whole thing has downloaded. So why does the order functions appear in my code matter?

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

EDIT: I think I may have found the answer.

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

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

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

I am groaning inside. Looks like I need to spend ANOTHER day re-ordering six thousand lines of code. The learning curve with javascript is not steep at all, but it is very loooooong.

我在里面呻吟。看起来我需要再花一天时间重新排序 6000 行代码。使用 javascript 的学习曲线一点也不陡峭,但它非常棒。

回答by Zirak

tl;drIf you're not calling anything until everything loads, you should be fine.

tl;dr如果你在一切加载之前都不打电话,你应该没问题。



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

编辑:有关还涵盖一些 ES6 声明 ( let, const)的概述:https: //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet

This weird behavior depends on

这种奇怪的行为取决于

  1. How you define the functions and
  2. When you call them.
  1. 你如何定义函数和
  2. 当你打电话给他们时。

Here's some examples.

这里有一些例子。

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

This is because of something called hoisting!

这是因为所谓的提升

There are two ways to define functions: Function declarationand function expression. The difference is annoying and minute, so let's just say this slightly wrong thing: If you're writing it like function name() {}, it's a declaration, and when you write it like var name = function() {}(or an anonymous function assigned to a return, things like that), it's a function expression.

定义函数有两种方式:函数声明和函数表达式。区别很烦人而且很细微,所以让我们说这有点错误:如果你像 那样写function name() {},它是一个声明,当你像这样写var name = function() {}(或分配给返回的匿名函数,类似的东西)时,它是一个函数表达式

First, let's look at how variables are handled:

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

var foo = 42;

//the interpreter turns it into this:
var foo;
foo = 42;

Now, how function declarationsare handled:

现在,如何处理函数声明

var foo = 42;
function bar() {}

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

The varstatements "throws" the creationof footo the very top, but doesn't assign the value to it yet. The function declaration comes next in line, and finally a value is assigned to foo.

var声明“抛出”的创作foo,以最顶端,但并不值分配给它。函数声明紧随其后,最后为 分配了一个值foo

And what about this?

而这个呢?

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

Only the declarationof foois moved to the top. The assignment comes only after the call to baris made, where it was before all the hoisting occurred.

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

And finally, for conciseness:

最后,为了简洁起见:

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

Now, what about function expressions?

现在,函数表达式呢?

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

Just like regular variables, first foois declaredat the highest point of the scope, then it is assigned a value.

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

Let's see why the second example throws an error.

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

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

As we've seen before, only the creating of foois hoisted, the assignment comes where it appeared in the "original" (un-hoisted) code. When baris called, it is before foois assigned a value, so foo === undefined. Now in the function-body of bar, it's as if you're doing undefined(), which throws an error.

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

回答by hugomg

The main reason is probably that JSLint does only one pass on the file so it doesn't know you willdefine such a function.

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

If you used functions statement syntax

如果您使用了函数语句语法

function foo(){ ... }

There is actually no difference at all where you declare the function (it always behaves as if the declaration is on the beginning).

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

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

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

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

You have to guarantee you wont call it before the initialization (this can actually be a source of bugs).

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



Since reordering tons of code is complicated and can be a source of bugs in itself, I would suggest you search for a workaround. I'm pretty sure you can tell JSLint the name of global variables beforehand so it doesn't complain about undeclared stuff.

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

Put a comment on the beggining of the file

对文件的开头发表评论

/*globals foo1 foo2 foo3*/

Or you can use a text box there for that. (I also think you can pass this in the arguments to the inner jslint function if you can meddle with it.)

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

回答by Henrik Vendelbo

There are way too many people pushing arbitrary rules about how JavaScript should be written. Most rules are utter rubbish.

有太多人在推行关于 JavaScript 应该如何编写的任意规则。大多数规则是彻头彻尾的垃圾。

Function hoisting is a feature in JavaScript because it is a good idea.

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

When you have an internal function which is often the utility of inner functions, adding it to the beginning of the outer function is an acceptable style of writing code, but it does have the drawback that you have to read through the details to get to what the outer function does.

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

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.

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

One coding style that you might see in the wild you should avoid because it gives you no advantages and only possible refactoring pain:

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

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

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

This is exactly what function hoisting is there to avoid. Just learn the language and exploit its strengths.

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

回答by Abhay Srivastav

Only function declaration are hoisted not function expression (assignment).

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