ホームページ  >  記事  >  ウェブフロントエンド  >  es6 ブロックレベルバインディングの let と const の詳細な分析

es6 ブロックレベルバインディングの let と const の詳細な分析

不言
不言転載
2019-03-30 09:43:182548ブラウズ

この記事は、es6 のブロックレベルバインディングにおける let と const の詳細な分析を提供します。一定の参考値があります。必要な友人は参照できます。お役に立てれば幸いです。

変数宣言は、常に js 作業の最も微妙な部分です。C 言語とは異なり、変数は作成時に常に宣言されます。js 言語では、変数を宣言する必要があるときに変数を宣言できます。

var let const 変数宣言

var 宣言と変数の昇格。

var キーワードを使用して変数を宣言する場合、変数がどこで宣言されているかに関係なく、関数の先頭で宣言されます (関数内にない場合はグローバルとみなされます) ) ドメインの先頭) これを変数巻き上げ(ホイスティング)といいます。

var は次のように巻き上げられます:

function getValue(condition) {
if (condition) {
var value = "blue";
// 其他代码
return value;
} else {
// value 在此处可访问,值为 undefined
return null;
}
// value 在此处可访问,值为 undefined
}

ブロックレベル宣言 let

ブロックレベル宣言は宣言された変数を許可します。指定されたスコープ外ではアクセスできません。ブロック レベルのスコープは、

  1. 関数内、
  2. コード ブロック内 (カーリーのペアで区切られた) ときに作成されます。 braces パッケージ)

let 宣言の構文は var 宣言と一致しています。let 宣言は変数を関数の先頭に昇格させないため、let 宣言を手動で配置する必要があります。変数をコード全体の先頭に配置できるように、ブロック内で使用できます。

以下に示すように:

function getValue(condition) {
if (condition) {
let value = "blue";
// 其他代码
return value;
} else {
// value 在此处不可用
return null;
}
// value 在此处不可用
}

識別子の重複は禁止されています

コード内で識別子が定義されている場合、let ステートメントを繰り返すとエラーが報告されます

var a = 30;
//报错
let a = 30;

変数は 2 回宣言されています。1 回目は var を使用し、もう 1 回目は let を使用します。 let は同じスコープ内の既存の識別子を再宣言できないため、ここでの let 宣言はエラーをスローします。一方、入れ子になったスコープ内で同じ名前の新しい変数を宣言するために let を使用してもエラーはスローされません。次のコードはこれを示しています:

var count = 30;
// 不会抛出错误
if (condition) {
let count = 40;
// 其他代码
}

このコードではエラーはスローされません。重要なのは、let が同じレベルのコード ブロック内で繰り返し宣言されている場合、エラーが報告されるということです。

const 定数宣言

は、es6 の const 構文を使用して宣言できます。 。 const を使用して宣言された変数は定数とみなされます。つまり、その値は設定後に変更できません。このため、すべての const 変数は宣言時に初期化する必要がありますが、

// 有效的常量
const maxItems = 30;
// 语法错误:未进行初始化
const name;

maxItems 変数は初期化されているため、その const 宣言は正常に動作します。 name 変数が初期化されていないため、このコードを実行しようとするとエラーがスローされました。 const 宣言は変数のバインドと自己生成値の変更を防止します。つまり、const 宣言は変数メンバーの変更を防止しません。例:

const person = {
name: "Nicholas"
};
// 工作正常
person.name = "Greg";
// 抛出错误
person = {
name: "Greg"
};

const 宣言と let 宣言の比較

  1. まず第一に、これらはブロックレベルの宣言であるため、定数をステートメント ブロックの外に置くことはできません。宣言されている場所にアクセスすると、宣言は昇格されません。例は次のとおりです:

if (condition) {
const maxItems = 5;
// 其他代码
}
// maxItems 在此处无法访问
  1. これらは、次の場合にエラーがスローされます。これらは統一されたスコープ内で繰り返し宣言されます

一時的なデッドゾーン

let または const を使用して宣言すると、宣言ポイントに到達するまでアクセスできません。アクセスしようとすると、引用エラーが発生します。この問題は一時的なデッド ゾーンが原因で発生します。

JS エンジンはコードの次のブロックを調べて変数宣言を見つけると、その宣言を var top の関数またはグローバル スコープにプロモートします。 let または const に直面すると、宣言は一時的なデッド ゾーンに置かれます。一時的なデッドゾーン内の変数にアクセスしようとすると、「実行時」エラーが発生します。変数の宣言ステートメントが実行された場合にのみ、変数は一時的なデッド ゾーンから削除され、安全に使用できるようになります。

ループ内のブロックレベルのバインディング

for (var i = 0; i < 10; i++) {
process(items[i]);
}
// i 在此处仍然可被访问
console.log(i); // 10

出力結果が期待値ではなく 10 になります。これは、var 宣言による変数の昇格が原因です。賢明な方であれば、ブロックレベルのバインディングを使用して変数を宣言することを間違いなく考えるでしょう

for (let i = 0; i < 10; i++) {
process(items[i]);
}

console.log(i);

i ここで出力は正常になりますか? 実際には正常ではありません。この例では、エラーが報告されます。なぜ?ここにはアクセスできないからです。この例の変数 i は for ループ内でのみ使用でき、ループが終了するとどこにもアクセスできなくなります。

コードを見てみましょう

var funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push(function() { console.log(i); });
}
funcs.forEach(function(func) {
func(); // 输出数值 "10" 十次
});

このコードが 0 から 9 までの値を出力すると予想したかもしれませんが、代わりに値 10 が同じ行に 10 回出力されます。これは、変数 i がループの各反復で共有されるためです。つまり、ループ内で作成された関数はすべて同じ変数への参照を持っていることになります。ループ終了後、変数 i の値は 10 になるため、console.log(i) が呼び出されるたびに 10 が出力されます。

この問題を解決するために、開発者は、次の例に示すように、ループ内で即時呼び出し関数式 (IIFE) を使用して、反復ごとに変数の新しいコピーを強制的に作成します。 # ループ内の let 宣言

let 宣言は、上記の例の IIFE の効果を効果的に模倣することでループを簡素化します。反復ごとに、同じ名前の新しい

変数が作成され、初期化されます。これは、IIFE を完全に省略して、次のように期待どおりの結果を得ることができることを意味します

var funcs = [];
for (let i = 0; i < 10; i++) {
funcs.push(function() {
console.log(i);
});
}
funcs.forEach(function(func) {
func(); // 从 0 到 9 依次输出
})

我们是否会想到这个问题:为什么同样的代码使用let声明会导致不一样的结果呢?
在循环中let声明每次都创建了一个新的i变量,因此在循环内部创建的函数获得了各自的i副本,而每个i副本的值都会在每次的循环迭代声明变量的时候确定了

var funcs = [],
object = {
a: true,
b: true,
c: true
};
for (let key in object) {
funcs.push(function() {
console.log(key);
});
}
funcs.forEach(function(func) {
func(); // 依次输出 "a"、 "b"、 "c"
});

本例中的 for-in 循环体现出了与 for 循环相同的行为。每次循环,一个新的 key 变量绑定就被创建,因此每个函数都能够拥有它自身的 key 变量副本,结果每个函数都输出了一个不同的值。而如果使用 var 来声明 key ,则所有函数都只会输出 "c" 。
let 声明在循环内部的行为是在规范中特别定义的,而与不提升变量声明的特征没有必然联系。事实上,在早期 let 的实现中并没有这种行为,它是后来才添加的。

循环内的常量声明

虽然es6没有明确的规范我们不能在for循环中使用const声明,然而它会根据循环方式的不同而有不同的行为,我们可以在初始化时使用const,但是当循环试图改变变量的值的时候会抛出错误,例如:

var funcs = [];
// 在一次迭代后抛出错误
for (const i = 0; i < 10; i++) {
funcs.push(function() {
console.log(i);
});
}

在此代码中, i 被声明为一个常量。循环的第一次迭代成功执行,此时 i 的值为 0 。在
i++ 执行时,一个错误会被抛出,因为该语句试图更改常量的值。因此,在循环中你只能使
用 const 来声明一个不会被更改的变量
而另一方面, const 变量在 for-in 或 for-of 循环中使用时,与 let 变量效果相同。因
此下面代码不会导致出错:

var funcs = [],
object = {
a: true,
b: true,
c: true
};
// 不会导致错误
for (const key in object) {
funcs.push(function() {
console.log(key);
});
}
funcs.forEach(function(func) {
func(); // 依次输出 "a"、 "b"、 "c"
});

这段代码与“循环内的 let 声明”小节的第二个例子几乎完全一样,唯一的区别是 key 的值在
循环内不能被更改。 const 能够在 for-in 与 for-of 循环内工作,是因为循环为每次迭
代创建了一个新的变量绑定,而不是试图去修改已绑定的变量的值(就像使用了 for 而不是
for-in 的上个例子那样)。

全局块级绑定

let 与 const 不同于 var 的另一个方面是在全局作用域上的表现。当在全局作用域上使用 var 时,它会创建一个新的全局变量,并成为全局对象(在浏览器中是 window )的一
个属性。

总结

let和const块级作用域的引入,能够使我们减少很多无心的错误,它们的一个副作用,是不能在变量声明位置之前访问它们

块级绑定当前的最佳实践就是:在默认情况下使用 const ,而只在你知道变量值需要被更改的情况下才使用 let 。这在代码中能确保基本层次的不可变性,有助于防止某些类型的错误。

本篇文章到这里就已经全部结束了,更多其他精彩内容可以关注PHP中文网的JavaScript视频教程栏目!

以上がes6 ブロックレベルバインディングの let と const の詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。