次のプログラムの結果は何ですか?
次の場合はどうでしょうか?
ショックを受けましたか?どうしたの?これは奇妙で、危険で、混乱を招くかもしれませんが、実際には非常に便利で印象的な JavaScript 言語機能でもあります。この動作に標準的な名前があるかどうかはわかりませんが、私はこの「ホイスティング」という用語が好きです。この記事ではこの仕組みについて入門的に説明しますが、その前に JavaScript の範囲について必要な理解をしておきましょう。
JavaScript の範囲
JavaScript の初心者にとって、最も混乱する点の 1 つはスコープです。実際、これは初心者だけではありません。私は何人かの経験豊富な JavaScript プログラマーに会ったことがありますが、彼らはスコープについて深く理解していません。 JavaScript のスコープがわかりにくい理由は、次の C プログラムのように、プログラム構文自体が C ファミリ言語に似ているためです:
多くの C、C、Java プログラマーにとって、これは期待し歓迎するものではありません。幸いなことに、JavaScript 関数には柔軟性があるため、これを回避する方法があります。一時的なスコープを作成する必要がある場合は、次のように作成できます:
変数の宣言、名前付け、プロモーション
JavaScript では、変数がスコープに入るには 4 つの基本的な方法があります。
•1 組み込み言語: すべてのスコープに this と引数があります (翻訳者注: テスト後、引数はグローバル スコープでは表示されません)
•2 仮パラメータ: 関数の仮パラメータは関数本体のスコープの一部になります。
•3 関数宣言: 次のような形式: function foo(){};•4 変数宣言: 次のように: var foo
関数宣言と変数宣言は、インタプリタによって常に静かにメソッド本体の先頭に「昇格」されます。これは、次のコードのようになります。
上記ではブーストの基本の一部を説明していますが、それほど混乱するものではないようです。ただし、一部の特殊なシナリオでは、依然としてある程度の複雑さが存在します。
変数の解析順序
心に留めておくべき最も重要なことは、変数解決の順序です。先ほど説明した、命名が範囲に入る 4 つの方法を覚えていますか?変数が解析される順序は、リストした順序です。
var a;
function a(){
}
alert(a);//a の関数本体を出力します
//ただし、注意 以下の 2 つの書き方との違いを区別してください:
<script><br>var a=1;<br>function a(){ <br>}<br>alert(a);//print out 1<br></script>
<script><br>function a(){ <br>}</p>
<p>var a=1;</p>
<p>alert(a);//print out 1<br></script>
1 組み込みの名前引数は、関数の仮パラメータの後、関数宣言の前に宣言する必要があるようです。これは、仮パラメータに引数がある場合、それが組み込みパラメータよりも優先されることを意味します。これは非常に悪い機能なので、仮パラメータでの引数の使用は避けてください。
2 この変数を任意の場所で定義すると構文エラーが発生しますが、これは良い機能です。3 複数の仮パラメータが同じ名前である場合、実際の操作中にその値が未定義であっても、最後のパラメータが優先されます。
名前付き関数
関数に名前を付けることができます。その場合、それは関数宣言ではなく、関数本体定義内の指定された関数名 (以下のスパムなど、翻訳者注記がある場合) は昇格されず、無視されます。理解に役立つコードを次に示します。
var baz = function spam() {};機能では、baz のみが昇格され、スパムは昇格されません。
foo(); // 有効な
spam(); // 参照エラー "スパムが定義されていません"
コードの書き方
スコープと変数ホイスティングについては理解できましたが、これは JavaScript コーディングにとって何を意味するのでしょうか?最も重要なことは、変数を常に var で定義することです。また、名前については、スコープ内に var 宣言を常に 1 つだけ含めることを強くお勧めします。これを行うと、スコープと変数のホイスティングの問題は発生しなくなります。
言語仕様の言い方
ECMAScript のリファレンス ドキュメントがいつも役に立ちます。スコープと変数ホイスティングについて私が発見したことは次のとおりです:
変数が関数本体クラスで宣言されている場合、それは関数スコープです。それ以外の場合は、(グローバルのプロパティとして) グローバルにスコープ設定されます。変数は、実行がスコープに入ると作成されます。ブロックは新しいスコープを定義せず、関数宣言とプロシージャ (翻訳者はグローバル コード実行であると考える) のみが新しいスコープを作成します。変数は作成時に未定義に初期化されます。変数宣言ステートメントに代入操作がある場合、代入操作は作成時ではなく実行時にのみ発生します。
この記事が、JavaScript について混乱しているプログラマーに一筋の光をもたらすことを願っています。私もこれ以上混乱を招かないように最善を尽くします。私が何か間違ったことを言ったり、何か見落としたりした場合は、お知らせください。
訳者補足
友人が、IE のグローバル スコープで名前付き関数を改善するという問題を発見したことを思い出させてくれました。
これは記事を翻訳するときにテストしたものです:
この質問により、他の 2 つの質問についても考えるようになりました。 1: スコープ上でグローバルに動作する変数の場合、var と非 var の間に違いがあり、var がないと、変数は昇格されません。たとえば、次の 2 つのプログラムのうち、2 番目のプログラムはエラーを報告します。