JavaScript関数の順序:なぜそれが重要なのですか?


106

元の質問:

JSHintは、JavaScriptが、呼び出しよりもページのさらに下で定義されている関数を呼び出すと、文句を言います。ただし、私のページはゲーム用であり、すべてがダウンロードされるまで関数は呼び出されません。では、なぜ注文関数がコードに表示されるのですか?

編集:私は答えを見つけたかもしれないと思います。

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

中がうめき声を上げている。別の日に6千行のコードを並べ替える必要があるようです。JavaScriptによる学習曲線はそれほど急ではありませんが、非常に緩やかです。


更新での優れた参照の+1。そして、コードを並べ替える必要がないことを納得していただければ幸いです。:)
awm

回答:


294

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

これは、巻き上げと呼ばれるものによるものです。

関数を定義するには、関数宣言と関数式の 2つの方法があります。違いは迷惑と分なので、ちょうどこの少し間違ったことを言ってみましょう:あなたのようにそれを書いている場合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されたと宣言、それは値が割り当てられ、範囲の最高点。

2番目の例がエラーをスローする理由を見てみましょう。

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 2018

6

主な理由は、おそらくJSLintがファイルに対して1つのパスしか実行しないため、そのような関数定義すること知らないためです。

関数ステートメント構文を使用した場合

function foo(){ ... }

実際には、関数を宣言する場所に違いはありません(常に宣言が最初にあるかのように動作します)。

一方、関数が通常の変数のように設定されている場合

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

初期化の前にそれを呼び出さないことを保証する必要があります(これは実際にはバグの原因となる可能性があります)。


大量のコードの並べ替えは複雑であり、それ自体がバグの原因となる可能性があるため、回避策を探すことをお勧めします。宣言されていないものについて文句を言わないように、JSLintにグローバル変数の名前を事前に伝えることができると確信しています。

ファイルの冒頭にコメントを付ける

/*globals foo1 foo2 foo3*/

または、そこにテキストボックスを使用できます。(これをいじることができる場合は、内部のjslint関数の引数でこれを渡すこともできると思います。)


ありがとう。/ *グローバル* /行は機能しますか?良い-JsHintが私を好きになるための何か 私はまだJavaScriptに不慣れで、ページを更新すると不可解な一時停止が発生しますが、バグは報告されていません。だから私は解決策がすべてのルールに従ってプレーし、それがまだ起こるかどうかを見ることだと考えました。
Chris Tolworthy、2011

4

JavaScriptの書き方について任意のルールを押している人が多すぎます。ほとんどのルールはまったくのゴミです。

関数の巻き上げは、良いアイデアであるため、JavaScriptの機能です。

内部関数のユーティリティであることが多い内部関数がある場合、それを外部関数の先頭に追加することは、コードを書くのに許容できるスタイルですが、詳細を読んで何に到達する必要があるという欠点があります。外側の関数が行います。

コードベース全体で1つの原則に固執する必要があります。プライベート関数をモジュールまたは関数の最初または最後に配置します。JSHintは一貫性を強制するのに適していますが、ソースコードを他の人の奇抜なコーディング概念に合わせて調整するのではなく、ニーズに合わせて絶対に.jshintrcを調整する必要があります。

実際に目にする可能性があるコーディングスタイルの1つは、利点がなく、リファクタリングの痛みが生じるだけなので、避ける必要があります。

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

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

これはまさに、関数の巻き上げが回避すべき機能です。言語を学び、その長所を活用するだけです。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.