JavaScript 函数顺序:为什么它很重要?
原始问题:
当我的 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
tl;dr 如果您在所有内容加载之前都没有调用任何内容,那么应该没问题。
编辑:有关还涵盖一些 ES6 声明(
let
、const
)的概述:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet这个奇怪的行为取决于
这里有一些例子。
这是因为一种叫做提升的东西!
定义函数有两种方式:函数声明和函数表达式。这种差异很烦人而且很微小,所以让我们说一下这个稍微错误的事情:如果你像
function name() {}
那样编写它,那么它是一个声明,并且当你可以像var name = function() {}
那样编写它(或者分配给返回值的匿名函数,类似的东西),它是一个函数表达式。首先,让我们看看如何处理变量:
现在,如何处理函数声明:
var
语句“抛出”创建foo
到最顶部,但尚未为其分配值。接下来是函数声明,最后将一个值赋给foo
。那这个呢?
只有
foo
的声明被移动到顶部。仅在调用bar
之后进行赋值,即在所有提升发生之前。最后,为了简洁起见:
现在,函数表达式怎么样?
就像常规变量一样,首先在作用域的最高点声明 foo,然后为其分配一个值。
让我们看看为什么第二个示例会抛出错误。
正如我们之前所看到的,只有
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_CheatsheetThis weird behavior depends on
Here's some examples.
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 likevar 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:
Now, how function declarations are handled:
The
var
statements "throws" the creation offoo
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 tofoo
.And what about this?
Only the declaration of
foo
is moved to the top. The assignment comes only after the call tobar
is made, where it was before all the hoisting occurred.And finally, for conciseness:
Now, what about function expressions?
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.
As we've seen before, only the creating of
foo
is hoisted, the assignment comes where it appeared in the "original" (un-hoisted) code. Whenbar
is called, it is beforefoo
is assigned a value, sofoo === undefined
. Now in the function-body ofbar
, it's as if you're doingundefined()
, which throws an error.主要原因可能是 JSLint 仅对文件执行一次传递,因此它不知道您将定义这样一个函数。
如果您使用函数语句语法,则
声明函数的位置实际上没有任何区别(它总是表现得好像声明位于开头)。
另一方面,如果您的函数设置为常规变量,
您必须保证在初始化之前不会调用它(这实际上可能是错误的来源)。
由于重新排序大量代码很复杂,并且本身可能是错误的来源,因此我建议您寻找解决方法。我很确定您可以事先告诉 JSLint 全局变量的名称,这样它就不会抱怨未声明的内容。
在文件的开头添加注释
或者您可以使用文本框来执行此操作。 (我还认为,如果您可以干预的话,您可以将其作为参数传递给内部 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
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
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
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.)
有太多人对 JavaScript 的编写方式提出武断的规则。大多数规则都是垃圾。
函数提升是 JavaScript 中的一项功能,因为它是一个好主意。
当您有一个内部函数(通常是内部函数的实用程序)时,将其添加到外部函数的开头是一种可接受的代码编写风格,但它确实有一个缺点,即您必须通读详细信息才能了解内容外部函数可以。
您应该在整个代码库中坚持一个原则,要么将私有函数放在模块或函数的前面或最后。 JSHint 对于强制一致性很有用,但您绝对应该调整 .jshintrc 以满足您的需求,而不是根据其他人古怪的编码概念调整您的源代码。
您可能会在野外看到一种应该避免的编码风格,因为它没有给您带来任何优势,只会带来重构的痛苦:
这正是函数提升要避免的。只需学习该语言并利用其优势即可。
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:
This is exactly what function hoisting is there to avoid. Just learn the language and exploit its strengths.
仅提升函数声明,而不提升函数表达式(赋值)。
Only function declaration are hoisted not function expression (assignment).