web-dev-qa-db-ja.com

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

元の質問:

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

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

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

私は中にうめいています。別の日を費やして6000行のコードを再注文する必要があるようです。 javascriptの学習曲線はそれほど急ではありませんが、非常に長いです。

100
Chris Tolworthy

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

これは、ホイストと呼ばれるものが原因です!

関数を定義するには、関数宣言と関数expressionの2つの方法があります。違いは煩わしくて分が小さいので、ちょっと間違ったことを言ってみましょう:function name() {}のように書いている場合、それは宣言、およびvar name = function() {}(またはリターンに割り当てられた匿名関数など)のように記述する場合、それは関数expression

最初に、変数の処理方法を見てみましょう。

_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ステートメントは、foocreationを最上部に「スロー」しますが、まだ値を割り当てていません。関数宣言は次に行に続き、最後にfooに値が割り当てられます。

これはどうですか?

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

foo宣言のみが最上部に移動します。割り当ては、barの呼び出しが行われた後にのみ行われます。この呼び出しは、すべての巻き上げが発生する前でした。

そして最後に、簡潔にするために:

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

さて、関数expressionsはどうですか?

_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()を実行しているかのようになり、エラーがスローされます。

278
Zirak

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

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

function foo(){ ... }

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

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

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

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


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

ファイルの開始にコメントを付けます

/*globals foo1 foo2 foo3*/

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

6
hugomg

JavaScriptの記述方法に関するarbitrary意的なルールを押し付ける人が多すぎます。ほとんどのルールは完全にゴミです。

関数ホイストはJavaScriptの機能です。なぜなら、それは良いアイデアだからです。

多くの場合、内部関数のユーティリティである内部関数がある場合、それを外部関数の先頭に追加することはコードの記述スタイルとして受け入れられますが、詳細を読んで目的を達成する必要があるという欠点があります外部関数が行います。

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

野生で見られるかもしれないコーディングスタイルの1つは、利点がなく、リファクタリングの苦痛だけをもたらすため、避ける必要があります。

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

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

これはまさに、関数の巻き上げを避けるためにあります。言語を学び、その長所を活用してください。

3
Henrik Vendelbo

関数式(割り当て)ではなく、関数宣言のみが上げられます。

2
Abhay Srivastav