記事ディレクトリ
はじめに:ES5のvar宣言変数の欠点
ES5は、実際には、変数を宣言する2つの方法を提供します。var
コマンドとfunction
コマンドです。function
コマンドを使用して関数を宣言する方法についてはここでは説明しませんvar
。主にコマンドを比較します。
以前、JSの概要var
で、コマンド宣言変数には3つの主要な特性があることを詳しく説明しました。
- 変数は繰り返し宣言できます。
- 変数宣言が促進されます。
- ブロックレベルのスコープはありません。
これらの3つの特性により、JSコードの記述は少し「ランダム」に見え、十分に標準化されていません。また、そのような文法ロジックも直感に反します。2つの例を挙げてください。
- 内側の変数は同じ名前の外側の変数
をカバーします。以下ではvar
、グローバル変数を宣言しnum
て値1を割り当て、次にshow
関数スコープのif
コードブロックでnum
変数を再宣言し、値2を割り当てます。
var num = 1;
function show() {
console.log(num);
if (false) {
var num = 2;
}
}
show();
——————OUTPUT——————
undefined
最終的なshow
関数実行の出力結果はundefined
です。
これは、var
宣言された変数にブロックレベルのスコープがなく、2番目の再宣言num
が関数の先頭に昇格し、同じ名前の外部グローバル変数をカバーするためです。この場合、出力結果はである必要がありますundefined
。(3つの特性すべてが1つの例に反映されています)
- さまざまなループ構造でカウントに使用されるループ変数は、グローバル変数としてリークされます。
ループ構造を使用する場合、ループ制御変数(i、j、kなど)を宣言しますが、ループが終了した後は消えません。 、グローバル変数にリークしました。
for (var i = 0; i < 3; i++) {
//...
}
console.log(i);
——————OUTPUT——————
2
より良いアプローチは、それがループ制御内でのみ有効であり、ループの終了後に自動的に失敗し、コードの他の部分の実行に影響を与えないことを期待することです。現時点では、ES6で新しいlet
コマンドを使用する必要があります。
1.基本を構築してみましょう
1.1letの基本的な使用法
let
コマンドは、ES6標準で変数を宣言するために使用される新しいコマンドです。その使命はvar
コマンドを置き換えることです。その使用法は似てvar
いますがvar
、設計上の欠陥を補います。
2つの最も基本的な違いは、let
コマンドが現在のコードブロックをブロックレベルのスコープとして宣言でき(以降の章で詳しく説明します)、let
コマンドによって宣言された変数は現在のコードブロックでのみ有効であるということです。
(コードブロックは中括弧のペアになっています{}
)
{
let a = 1;
var b = 2;
}
a // ReferenceError: a is not defined.
b // 2
コードブロック外の変数にアクセスするa
と、未定義のエラーが報告var
されb
ますが、定義済みの変数を使用しても引き続きアクセスできます。
これで、このlet
コマンドを使用して、この記事の冒頭にある2番目の問題であるループ変数リークの問題を解決できます。for
ループカウンターのステートメントをi
使用しますlet
:
for (let i = 0; i < 3; i++) {
//...
}
console.log(i);
——————OUTPUT——————
// ReferenceError: i is not defined
現時点でi
は、変数にアクセスできません。
❀少し拡大(1)❀
ループでlet
コマンドを使用するときに注意すべきもう1つのポイントがあります。変数i
は、ループ内で毎回再宣言されます。
まず、var
宣言されたループ変数の使用法を確認し、i
各ループにタイマー関数を追加して、このループ変数を出力しますi
。
for(var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
——————OUTPUT——————
3
3
3
forループ全体のループ変数はi
常に同じ変数であり、最後にループ終了変数i
に値2が割り当てられるため、3つの3が出力されます。次に、let
コマンドに変更して、もう一度出力します。
for(let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
——————OUTPUT——————
0
1
2
出力結果は、timer関数を使用しない場合と同じであることがわかります。これは、変数i
がループ内で毎回再宣言されるためです。通常のロジックに従って出力される理由は、JavaScriptエンジンが前のループラウンドの値を記憶するためです。 、このラウンドの変数を初期化するとき、i
計算は前のラウンドに基づいて実行されます。
❀少し拡大(2)❀
forループ自体には、別の特別な機能があります。ループ変数を設定する部分は親スコープであり、ループ本体の内部は別の子スコープです。
for (let i = 0; i < 3; i++) {
let i = 'zevin';
console.log(i);
}
——————OUTPUT——————
zevin
zevin
zevin
3回出力されましたzevin
。これは、ループ本体内の変数i
とループ変数i
が同じスコープ内になく、独自の個別のスコープを持っていることを示しています。
1.2constの基本的な使用法
const
このコマンドは、読み取り専用定数を宣言するために使用されます。宣言の最初に割り当てる必要があり、宣言後に変更することはできません。
const PI;
// SyntaxError: Missing initializer in const declaration
const PI = 3.1415926;
PI = 3.14;
// TypeError: Assignment to constant variable.
❀展開❀
constコマンドの本質
constコマンドが実際に保証するのは、変数の値を変更できないということではなく、変数が指すメモリアドレスに格納されているデータを変更できないということです。
基本的なタイプの単純なデータ(数値、文字列、ブール値)の場合、変数が指すメモリアドレスには値自体が格納されるため、変更できない変数の値と同等です。
const obj = {
};
// 可以添加属性
obj.name = 'zevin';
console.log(obj.name);
// zevin
// 让obj指向另一个对象就会报错
foo = {
};
// TypeError: "obj" is read-only
参照データタイプ(主に配列、オブジェクト)の場合、変数が指すメモリアドレスは参照アドレスを保存しますが、参照アドレスは変更できません。配列、オブジェクト自体については、引き続き追加または削除できます。素子。
2.ES6変数宣言の新しい仕様
声明ES5するvarコマンドではなく、規範的なJS言語を向上させるために、状況を改善するために、ES6は、次の4つの新しい変数宣言規範を提案し、let
そしてconst
コマンドが適用されます。
2.1ブロックレベルのスコープ
ES5にはグローバルスコープと関数スコープしかありません。最後に、ブロックレベルのスコープがES6に追加されました。使用let
またはconst
ブロックレベルのアクションコマンドの変数は、ドメインが有効である唯一の文で宣言されました。
{
let a = 1;
if(true){
const a = 2;
};
console.log(a);
}
——————OUTPUT——————
1
コードブロックは{}
、相互に影響を与えることなく任意にネストできる1対の中括弧に基づいています。
{
{
{
{
{
const name = 'zevin' }
console.log(name);
// 报错
}}}};
上記のコードは、5レベルのブロックレベルのスコープを使用しています。各スコープは個別のスコープです。第4レベルのスコープは、第5レベルのスコープの内部変数を読み取ることができません。
2.2可変プロモーションはありません
var
コマンドによって宣言された変数は、ドキュメントの先頭または関数の先頭にプロモートされます。つまり、変数は宣言の前に使用でき、値はundefined
です。そして、行動ES6で固定文法、let
およびconst
変数コマンドがそれ以外の場合はエラー、使用後の文で宣言しなければなりません。
console.log(a);
console.log(b);
console.log(c);
var a = 1;
let b = 2;
const c = 3;
——————OUTPUT——————
undefined
ReferenceError: Cannot access 'b' before initialization
ReferenceError: Cannot access 'c' before initialization
2.3一時的なデッドゾーン
ES6は、ブロックが存在しlet
、const
コマンドを実行する場合、これらのコマンドの変数宣言を最初からブロックして、閉じたスコープを形成することを明確にします。これらの変数が宣言の前に使用されている場合、エラーが報告されます。これは文法的に「一時的なデッドゾーン」(略してTDZ)と呼ばれます。
if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError
let tmp; // TDZ结束
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}
上記のコードでは、let
コマンドが変数を宣言する前にtmp
、すべてが変数tmp
の「デッドゾーン」に属しています。
❀展開❀
「一時的なデッドゾーン」の出現は、typeof
エラーを報告することのない操作ではなくなったことも意味します。
typeof a; // undefined
typeof b; // ReferenceError
const b = 1;
変数を宣言b
するconst
前の変数の使用b
は、その変数のエラーを使用する限り、「デッドゾーン」に属します。したがって、typeof
オペレーターはReferenceError
エラーをスローします。
ただし、変数がまったく宣言されていない場合(variable a
)typeof
、使用してもエラーは報告されませんundefined
。
2.4重複した宣言は許可されていません
ES6では、同じスコープ内で同じ変数を複数宣言することはできません。
if(true){
var a = 1;
let a = 2;
const a = 3;
}
// SyntaxError: Identifier 'a' has already been declared
したがって、同様に、仮パラメータと同じ名前の変数を関数で使用let
またはconst
コマンドすることはできませんが、使用するvar
ことはできます。
function func(num) {
let num = 1;
console.log(num);
}
func()
// SyntaxError: Identifier 'num' has already been declared
function func(num) {
var num = 1;
console.log(num);
}
func()
// 1
異なるブロックレベルのスコープは相互に影響を与えないため、異なるブロックレベルのスコープで同じ名前の変数を定義できます。したがって、次のコードはエラーを報告しません。
function func(num) {
var num = 1;
if(true){
let num = 2;
}else{
const num =3;
}
}
func()
3.拡張機能:ES6で変数を宣言する6つの方法
ES5 | ES6 |
---|---|
var 関数 |
聞かせて constの インポート クラス |
ES6は、実際には、4つの新しい変数宣言メソッドです。このペーパーでは、let
コマンドとconst
コマンドを紹介し、続いて、コマンドとコマンドを再度紹介しimport
ますclass
。ES5のvar
コマンドおよびfunction
コマンドと組み合わせて、ES6で変数を宣言する6つの方法があります。