ES6 ラーニング 1
1. 変数宣言
ES6 には、変数を宣言する方法が合計 6 つあります。つまりvar
、function
、let
、const
、import
、class
です。var
コマンドはes5と違いはなく、今日は記録とコマンドfunction
がメインです(コマンドはよく理解していないので後ほど追記します)。let
const
import
class
1.1 letコマンド
機能: 変数を宣言します。ただし、宣言された変数は let コマンドが配置されているブロックレベルのスコープ内で有効であることを意図しており、変数の昇格はありません。
// 只声明
let a
// 声明时赋值
let b = 1
// 声明后赋值
let c
c=2
console.log(a); // undefined
console.log(b); // 1
console.log(c); // 2
1.2 constコマンド
機能: let コマンドと同様に定数を宣言します。
宣言時の代入による初期化
let コマンドと比較すると、定数は一度宣言すると値を変更できないため、宣言時に代入して初期化する必要があります。
// 只声明
const a // SyntaxError: Missing initializer in const declaration
console.log(a); // 不执行
オブジェクトや配列などの参照型のデータ
これらのデータのアドレスは実際のデータへのポインタを保存するため、これらのデータの内容を変更することができます。
ただし、オブジェクトまたは配列全体を直接置換または再割り当てすると、その実際のアドレスが変更され、エラーが報告されます。
const aoo = {
a: 1}
aoo.a = 2
aoo.b = 1
console.log(aoo); // { a: 2, b: 1 }
aoo = {
c: 3 }
console.log(aoo); // 不执行
オブジェクトをフリーズする
オブジェクトを不変にするには、次を使用できますObject.freze()
const aoo = Object.freze({
a: 1}) // TypeError: Object.freze is not a function
aoo.a = 2 // 以下不执行
aoo.b = 1
console.log(aoo);
1.3 ブロックレベルのスコープ
ES6 ではブロック レベル スコープが追加されました。 が存在する限り{}
、{}
それはブロック レベル スコープを表します。使用let
およびconst
宣言された変数は、現在のブロック レベル スコープで使用されます。
ブロックレベルのスコープがないため、内部変数がグローバル変数としてリークする
es5ではグローバルスコープと関数スコープ(関数によって開かれるスコープ)しかないため、内部変数がグローバル変数として漏洩してしまいます(例:loop)
var s = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
ブロックレベルのスコープがないため、ループのみに使用される内部変数がi
グローバル変数としてリークされます。
let s = 'hello';
for (let i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // ReferenceError: i is not defined
ブロックレベルのスコープは、ループとして使用される内部変数がスコープ内にのみ存在するように制限し、外部層にはこの変数i
がありません。i
変数を二重宣言することはできません
同じブロックレベルのスコープ内では、変数を繰り返し宣言することはできません。宣言しないとエラーが報告されます。
let a
let a = 1 // SyntaxError: Identifier 'a' has already been declared
1.4 可変ブーストなしと一時的な不感帯
変数の昇格es5 やvar
コマンドを使用する場合、宣言前でも変数を使用できますが、値は未定義です。
内部変数が外部変数をオーバーライドする変数プロモーションがあります。
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
変数promotion()で宣言されたtmpが外側のtmpの値を上書きするため
let tmp = new Date();
function f() {
console.log(tmp);
if (false) {
let tmp = 'hello world';
}
}
f(); // 2021-08-18T18:20:32.471Z
変数の昇格がない場合、外側の tmp の値は取得された時間のままです
es6 の使用let
およびconst
コマンドでは変数のプロモーションが許可されておらず、宣言された変数は宣言後に使用する必要があります (typeof を含む)。そうでない場合はエラーが報告されます。
console.log(s); // ReferenceError: Cannot access 's' before initialization
let s = 'hello';
このエラー プロンプトは一時的なデッド ゾーンです。
一時的なデッドゾーン
一時的なデッドゾーンは、letコマンドやconstコマンドを使用する際に閉じたスコープを形成するためのもので、変数宣言位置が「デッドゾーン」になる前は、宣言位置以降のみ変数を使用できます。
typeof を使用する場合、宣言されていない変数はエラーを報告しませんが、宣言された変数が宣言の前に使用された場合はエラーを報告することに注意してください。
console.log(typeof a); // undefined
console.log(typeof b); // ReferenceError: Cannot access 'b' before initialization
let b = 'b'
2. 変数の分解、代入、エイリアスの設定
分解: ES6 では、配列やオブジェクトから値を抽出し、特定のパターンに従って変数に値を割り当てることができます。
基本的にこの書き方はパターンマッチングに属し、両側のパターンが同じであれば左側の変数に対応する値が代入されます。
let [a, b] = [1, 2]
console.log(a); // 1
console.log(b); // 2
不完全な解体
ただし、es6 では左側と右側のパターンが完全に同じである必要はないため、等号の左側のパターンは等号の右側のパターンの一部とのみ一致し、不完全な分解が行われます。つまり、一致する部分的な分解代入は成功し、一致しない部分的な分解は失敗し、変数の値は未定義に等しくなります。
let [a, [b,c],d] = ['1', '2', '3']
console.log(a); // 1
console.log(b); // 2
console.log(c); // undefined
console.log(d); // 3
?等号右側の配列の値がNumber型の場合、等号の両側のモードが異なるとエラーとなります。
let [a, [b,c],d] = [1, 2, 3] // TypeError: undefined is not a function
console.log(a); //以下不执行
console.log(b);
console.log(c);
console.log(d);
2.1 異なるタイプのデータの割り当ての分割
オブジェクト分割割り当て
オブジェクトはキーの値に従って分解され、キーは自由に交換できます
let {
b, a, c } = {
a: 1,b:2}
console.log(a); // 1
console.log(b); // 2
console.log(c); // undefined
配列の構造化代入
配列は 1 対 1 対応の順序に従って分解され、自由に位置を交換することはできません。配列の添字がオブジェクトのキー値であると想像できますが、順序が違えばキーも異なるため、自由に位置を入れ替えることはできません。
// let [a, b] = [1, 2]
// console.log(a); // 1
// console.log(b); // 2
let [b, a] = [1, 2]
console.log(a); // 2
console.log(b); // 1
ただし、配列はオブジェクトの方法で特別なオブジェクトとして構造を解除することもできます。
let {
1: b, 0: a } = [1, 2]
console.log(a); // 1
console.log(b); // 2
文字列の分割代入
文字列は配列のようなオブジェクトに変換され、配列の形式で構造化されます。
let [a, [b, c], d, e, f] = 'hello'
console.log(a); // h
console.log(b); // e
console.log(c); // undefined
console.log(d); // l
console.log(e); // l
console.log(f); // o
オブジェクトの形で特別なオブジェクトとして分解することもできます。
let {
0:a, 1:b, 2:c, 3:d, 4:e } = 'hello'
console.log(a); // h
console.log(b); // e
console.log(c); // l
console.log(d); // l
console.log(e); // o
数値およびブール値の代入の構造化
数値とブール値はラッパー オブジェクトに変換され、オブジェクトの方法で構造化されます。
let {
toString: s} = 123;
s === Number.prototype.toString // true
let {
toString: s} = true;
s === Boolean.prototype.toString // true
未定義および null の代入の構造化
代入を分割するためのルールは、右側が配列、オブジェクト、または配列のようなオブジェクト値でない場合は常に、最初にそれをオブジェクトに変換することです。未定義および null はオブジェクトに変換できないため、分解および代入時にエラーが報告されます。
// let { prop: x } = undefined; // TypeError: Cannot destructure property 'prop' of 'undefined' as it is undefined.
let {
prop: y } = null; // TypeError: Cannot destructure property 'prop' of 'null' as it is null.
関数パラメータの割り当ての構造化
関数パラメータは、さまざまなデータ型に応じて上記のルールに従って構造を分解して割り当てることができます。
[{
name: 'a'},{
name: 'b'},{
name: 'c'}].map(({
name}) => name)
2.2 デフォルト値
場合によっては、分解時にデフォルト値を用意し、分解が失敗した場合、または実際に未定義に等しい場合にこのデフォルト値を使用したいことがあります。
es6 は内部的に厳密等価演算子 (===) を使用して位置に値があるかどうかを判断するため、デフォルト値は、分解に失敗した未定義と厳密に等しい場合にのみ有効になります。
let {
a='01', b='02', c='03' } = {
a: 1, b: 2}
console.log(a); // 1
console.log(b); // 2
console.log(c); // 03
NULL値
規則によれば、null 値で表される位置に値がある場合、その値は null となり、デフォルト値は有効になりません。
let {
a='01', b='02', c='03' } = {
a: 1, b: 2, c: null}
console.log(a); // 1
console.log(b); // 2
console.log(c); // null
デフォルト値の参照により他の変数が構造化されます
デフォルト値は構造化されていない他の変数を参照できますが、変数は宣言されている必要があります。
let [x = 0, y = x] = []
console.log(x); // 0
console.log(y); // 0
x は y が宣言される前に宣言され、値 0 が割り当てられているため、y は x をデフォルト値として使用できます。
let [x = y, y = 0] = [] // ReferenceError: Cannot access 'y' before initialization
console.log(x); // 以下不执行
console.log(y);
x は、変数のプロモーションがないため、y が宣言される前に y をデフォルト値として使用し、エラーが報告されます。
2.3 エイリアス
変数名が属性名と異なる場合は、変数名を属性名のエイリアスとして設定する必要があります。
let {
message: msg } = {
message:'123' }
console.log(msg); // 123
console.log(message); // ReferenceError: message is not defined
実は私が普段書いているのはlet {foo} = {foo:123}
、let {foo:foo} = {foo:123}
オブジェクトの分解と代入の内部メカニズムでは、まず同じ名前の属性を見つけて、それを対応する変数に代入しますが、実際には前者ではなく後者が代入されます。