JS には変数プロモーションがあります。この設計は実際には不十分、または言語実装の副作用です。これにより、変数を宣言せずにアクセスしたり、後で宣言して最初に使用したりすることができます。初心者はこれに混乱し、長年 JS を使用してきた多くのベテランさえも混乱します。しかし、ES6 が let/const を追加した後、変数 Hoisting は存在しなくなりました。
1. 変数は宣言されていないため、直接使用します
function test() { alert(notDefined); } test(); // ?
エラーを報告するのは当然です
2. 最後に変数宣言
function test() { alert(declaredButNotAssigned); // undefined var declaredButNotAssigned; } test();
出力は未定義です。結果は上記の例と比較して改善されており、エラーは報告されず、コードは実行できますが、変数値はプログラマが期待したものではない可能性があります。
3. 最後に変数を宣言し、同時に変数に値を代入します
function test() { alert(declaredAndAssigned); // undefined var declaredAndAssigned = 1; } test();
結果は 2 と同じですが、代入しただけでは 1 が出力されるわけではありません。
2 と 3 は両方とも、単純に定義された変数ホイスティング (ホイスティング) を持っています
変数の昇格: 指定されたスコープでは、コード順序に関して、変数は最初に使用され、次に宣言されますが、実行時の変数の「アクセス可能性」は現在のスコープの先頭に昇格され、その値は未定義です、そして「可用性」はありません。
ここで重点を置くのは「コードの順序」と「実行順序」です。これは、ほとんどの場合、作成したコードは順番に実行されるため、つまり、「コードの順序」と「実行順序」が一貫しているためです。これは人間の脳の思考プロセスとも一致します。例:C言語の経験のあるプログラマー
#include <stdio.h> int main() { int x = 1; printf("%d, ", x); // 1 }
2 行のコードで、最初に整数型 x を宣言してから、それを出力します。コードシーケンスと実行シーケンスは一貫しています。つまり、正常に動作します。
順序が逆の場合
#include <stdio.h> int main() { printf("%d, ", x); // error int x = 1; }
この時点では、コンパイルを通過できません。ただし、JS では逆に記述することもできます。2 と 3 を参照してください。
したがって、C 系言語の経験のあるプログラマーは、変数を最初に宣言してから使用する必要があることを知っています。そうしないと、エラーが報告されます。 JS では、変数のプロモーションという現象があり、これを最初に使用してから宣言することができ、C の経験が JS で使用され、混乱が生じます。
4. 関数式にも変数プロモーションがあります
function test() { alert(func); // undefined var func = function() {}; } test();
しかし、この関数を使用したい場合は、それは不可能です
function test() { alert(func); // undefined func(); // 报异常 var func = function() {}; } test();
結果の func は未定義であり、func を呼び出すと例外が報告されます。 アクセシビリティと可用性は上記の定義で言及されており、次の記述に対応します。
アクセシビリティ:alert(func)、出力は未定義、実行可能、func にアクセス可能。
可用性: func() は例外を報告し、func は正常に呼び出すことができず、可用性がないことを示します。
2番目、3番目、4番目はすべてvarを使用して宣言された変数です。JSの関数宣言も改良されますが、この「変数」は関数型です(関数、メソッド、またはコンストラクタとして使用できます)。 。その名前 (識別子) も現在のスコープの先頭に引き上げられます。
5. 関数宣言の名前も現在のスコープの先頭に昇格されます
function test() { alert(f1); // function f1(); // "called" function f1() { alert('called'); } } test();
f1 がコードの最後で宣言され、f1 が最初に使用されることがわかります。alert(f1) と f1() の両方が正常に実行され、アクセシビリティと使いやすさの両方が存在することがわかります。
前に述べたように、変数の巻き上げは役に立ちません。「最初に宣言してから使用する」のが良い習慣です。この機能は大企業の面接の質問にも多く登場します
質問 1:
// 写出以下代码的运行结果 var a = 1; function fn() { if (!a) { var a = 2; } alert(a); // ? } fn();
質問 2:
// 写出以下代码的运行结果 var a = 1; function fn() { a = 2; return; function a() {} } fn(); alert(a); // ?
しかし、これは ES6 の let/const の登場ですべて終わりました。グローバル変数を除いて、ES の他のすべてのものは let/const を使用します。var を let に置き換えた後は、変数の昇格は存在しません。
function test() { alert(declaredButNotAssigned1); // 报异常 alert(declaredButNotAssigned2); // 报异常 alert(func); // 报异常 let declaredButNotAssigned1; let declaredButNotAssigned2 = true; let func = function() {}; } test();
これにより、プログラマは変数を「最初に宣言してから使用する」という良い習慣を身につけなければなりません。そうしないと、エラーが報告されます。
以下は、let が発生しない場合の変数昇格に関する MDN の説明からの抜粋です
let を使用して変数を宣言した後、typeof は安全ではなくなりました
if (condition) { alert(typeof num); // Error! let num = 100; }
以前は、typeof == 'unknown' を使用して、jQuery などの特定のライブラリが導入されたかどうかを判断できました
// 判断jQuery是否引入了 if (typeof $ !== 'undefined') { // do something }...
jQuery は導入されておらず、$ も宣言されていないため、この文はエラーを報告せず、次のコードの実行に影響を与えませんが、let で宣言されている場合はエラーが報告されます。
以上がこの記事の全内容です。皆さんに気に入っていただければ幸いです。