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

发布于 2024-12-07 03:16:56 字数 451 浏览 1 评论 0原文

原始问题:

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

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

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

我在内心呻吟。看来我需要再花一天时间重新排序六千行代码。 javascript 的学习曲线一点也不陡峭,但是非常漫长。

Original Question:

JSHint complains 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?

EDIT: I think I may have found the answer.

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

╭ゆ眷念 2024-12-14 03:16:56

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 语句“抛出”创建 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() 一样,这会引发错误。

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


Edit: For an overview which also covers some ES6 declarations (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.

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 declaration and 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.

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 declarations are handled:

var foo = 42;
function bar() {}

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

The var statements "throws" the creation of foo to 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.

And what about this?

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

Only the declaration of foo is moved to the top. The assignment comes only after the call to bar is made, where it was before all the hoisting occurred.

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 foo is declared at the highest point of the scope, then it is assigned a value.

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 foo is hoisted, the assignment comes where it appeared in the "original" (un-hoisted) code. When bar is called, it is before foo is 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.

浮云落日 2024-12-14 03:16:56

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

如果您使用函数语句语法,则

function foo(){ ... }

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

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

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

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


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

在文件的开头添加注释

/*globals foo1 foo2 foo3*/

或者您可以使用文本框来执行此操作。 (我还认为,如果您可以干预的话,您可以将其作为参数传递给内部 jslint 函数。)

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

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.

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.)

美煞众生 2024-12-14 03:16:56

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

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

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

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

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

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

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

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

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

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

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.

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.

别靠近我心 2024-12-14 03:16:56

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文