抹桥的博客
Language
Home
Archive
About
GitHub
Language
主题色
250
2179 文字
11 分
ECMAScript6 学習メモ(1)- 変数宣言・文字列拡張・数値拡張

let と const コマンド#

let コマンド#

let で宣言された変数は、宣言されたコードブロック内でのみ存在します。

{
  let a = 10;
  var b = 11;
}
console.log(a); //ReferenceError: a is not defined
console.log(b); //11

ご覧の通り、コードブロックの外からは let で宣言された変数にアクセスすることはできません。つまり、let で宣言された変数はブロックスコープに基づいています。これにより、いくつかの変数宣言の問題を回避できます。

var arr = [1, 2, 3];
for (let i = 0; i < arr.length; i++) {}
console.log(i); //ReferenceError: a is not defined

上記のコードでは、for ループの外からは変数 i にアクセスできないことがわかります。

一方、以下のコードは var で宣言されており、最終的に 10 を出力します。

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

しかし let を使用すると 6 が出力されます。以前はこれを実現するために、即時実行関数が必要だったかもしれません。

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

さらに、letvar のように「巻き上げ(hoisting)」現象は発生しません。

function a(){
    console.log(b)  //ReferenceError
    let b = 2;
}
function c(){
    console.log(d); //undefined
    var d = 2;

ブロックスコープ内では、let で宣言された変数はその領域に固定され、外部の影響を受けません。

var temp = 123;
let temp1 = 222;
var temp2 = 555;
if (true) {
  let temp = 333;
  let temp1 = 444;
  console.log(temp); //333
  console.log(temp1); //444
  console.log(temp2); //ReferenceError
  let temp2 = 555;
}

let は、一つのスコープ内で同じ変数を再宣言することを許可しません。

function(){
    let a = 10;
    var a = 1;
}
function(){
    let a = 11;
    let a = 212;
}

const コマンド#

constlet と似ていますが、const で宣言された変数は定数であり、一度宣言されると変更できません。

const a = 1;
a; //1
a = 3;
a; //1
const a = 12;
a; //1

注意すべき点として、const コマンドは変数が存在するアドレスを指すだけなので、オブジェクトを定数として宣言する際には注意が必要です。

const foo = {};
foo.prop = 1;
foo.prop; //1
const a = [];
a.push("Hello"); // 可执行
a.length = 0; // 可执行
a = ["Dave"]; // 报错

上記のコードでは、定数 foo はアドレスを格納しており、このアドレスはオブジェクトを指しています。不変なのはこのアドレスだけであり、foo を別のアドレスに再割り当てすることはできません。しかし、オブジェクト自体は可変であるため、新しいプロパティを追加することは可能です。

つまり、オブジェクトや配列を定数として宣言した場合、それ自体を再割り当てすることはできませんが、メソッドを追加することは可能です。なぜなら、不変なのはそのアドレス自体だからです。

グローバルオブジェクトのプロパティ#

ES6 の規定では、var コマンドと function コマンドで宣言されたグローバル変数はグローバルオブジェクトのプロパティに属します。一方、let コマンド、const コマンド、class コマンドで宣言されたグローバル変数はグローバルオブジェクトのプロパティには属しません。

var a = 1;
// 如果在node环境,可以写成global.a
// 或者采用通用方法,写成this.a
window.a; // 1
let b = 1;
window.b; // undefined

変数の分割代入#

ES6 では、特定のパターンに従って配列やオブジェクトから値を取り出し、変数に代入することが許可されており、これを「分割代入(destructuring assignment)」と呼びます。この点は Python によく似ていると感じます。

配列の分割代入#

var [a, b] = [1, 2];
console.log(a, b);
//1 2
let [c, d] = [3, 4];
console.log(c, d);
//3 4

実際には、これは「パターンマッチング」に属します。つまり、等号の両側のパターンが同じであれば、左側の変数には対応する値が割り当てられます。

var [a, b, [c, d]] = [1, 2, [3, 4]];
//a = 1,b = 2,c = 3,d = 4
var [aa, bb, cc] = [, , 3];
//aa = undefined,bb = undefined,cc = 3;
let [one, ...more] = [1, 2, 3, 4, 5, 6];
//one = 1,more = [2,3,4,5,6]

上記のコードからわかるように、構造が同じであれば、左側の対応する位置の変数には右側の対応する値が代入されます。対応する値がない場合は undefined になります。 以下のケースは分割代入が失敗する例であり、いずれも TypeError が発生し、変数の値は undefined になります。

上記のいくつかのケースはすべて分割代入が失敗する例であり、foo の値は undefined になります。これは、プリミティブ型の値が自動的にオブジェクトに変換されるためです(例えば、数値 1new Number(1) に変換される)、その結果 fooundefined を取得することになります。

var [foo] = [];
var [foo] = 1;
var [foo] = false;
var [foo] = NaN;
var [bar, foo] = [1];
let [foo] = undefined;
let [foo] = null;

分割代入ではデフォルト値を指定できます。配列のメンバーが厳密に undefined と等しい場合に、デフォルト値が有効になります。

var [foo = true] = [];
foo[(x, (y = "b"))] = // true
  ["a"][(x, (y = "b"))] = // x='a', y='b'
  ["a", undefined][(x, (y = "b"))] =
    // x='a', y='b'
    [1, null]; // x= 1,y=null

オブジェクトの分割代入#

分割代入はオブジェクトにも同様に適用されます。配列との違いは、配列の要素の値はその位置によって決まるのに対し、オブジェクトのプロパティには順序がないため、正しい値を取得するには変数名がプロパティ名と同じである必要がある点です。

var { foo, bar } = { foo: "aaa", bar: "bbb" };
foo; // "aaa"
bar; // "bbb"
//注意两者区别
var { foo, bar } = { bar: "aaa", foo: "bbb" };
foo; // "bbb"
bar; // "aaa"
var { fos } = { foo: "aaa" };
fos; // undefined

上記のコードからわかるように、代入はプロパティ名のみに関係し、順序には関係ありません。プロパティ名が一致しない場合、値は undefined になります。 変数名とプロパティ名が一致しない状況で代入を行う必要がある場合は、以下の方法を使用します。

var { foo: abs } = { foo: "sss" };
abs; // 'sss'

同様に、ネストされた構造を持つオブジェクトも分割代入できます。

let obj = {
  p: ["Hello", { y: "World" }],
};
let {
  p: [x, { y }],
} = obj;
console.log(x, y);
//Hello World

配列と同様に、オブジェクトの分割代入でもデフォルト値を指定できます。代入対象のオブジェクトに対応するプロパティが厳密に undefined と等しい場合に、デフォルト値が適用されます。

var { a = 3 } = {};
a; //3
var { b = 4, y } = { y: 4 };
(b, y); //4,4

オブジェクトの分割代入は、私たちに大きな利便性をもたらします。

var obj = {
  method1: function () {},
  method2: function () {},
};
var { method1, method2 } = obj;
//以前的写法
var method1 = obj.method1;
var method2 = obj.method2;

文字列の分割代入#

文字列も同様に分割代入が可能です。分割代入を行う際、文字列は配列ライクなオブジェクトに変換されます。

let [f, g, h] = "length";
console.log(f, g, h);
//l,e,n
let { length: len } = "length";
console.log(len);
//6

関数引数の分割代入#

関数引数は配列ライクなオブジェクトであり、同様に分割代入が可能です。

function a([x, y]) {
  return x + y;
}
add([1, 2]); //3

同様にデフォルト値を設定することもできます。

function move({x=0,y=0}={}){
    "use strict";
    console.log([x,y]);
}
move({x:3,y:4});        //[3,4]
move({x:3});            //[3,0]
move({});               //[0,0]
move();                 //[0,0]
function remove({x,y}={x:0,y:0}){
    "use strict";
    console.log(x,y);
}
remove({x:1,y:2});      //1,2
remove({x,y});          //Hello World
remove({});             //undefined undefined
remove();               // 0 0

関数引数の分割代入方法は、引数の型に基づいて自動的に選択されます。配列であれば配列の分割代入、オブジェクトであればオブジェクトの分割代入が適用されます。

function fc([x,y,z]){
    "use strict";
    console.log(x,y,z);
}
fc([1,2,3]);     //1,2,3
function nf({x,y,z}){
    "use strict";
    console.log(x,y,z);
}
nf({y:1,z:2,x:3});    //3,1,2

用途#

JSON データの抽出#

var jsonDate = {
  id: 42,
  status: "notOK",
  data: [12, 32],
};
let { id, status, data } = jsonDate;
console.log(id, status, data); //42 'notOK' [12,32]

Map 構造のイテレーション#

var map = new Map();
map.set("first", "HELLO");
map.set("second", "WORLD");
for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is HELLO
// second is WORLD
for (let key of map) {
  console.log(key);
}
//['first','HELLO']
//[ 'second', 'WORLD' ]

著作権#

記事内のすべてのコードは以下から引用または派生しています:

阮一峰 - ECMAScript 6 入門, 本記事も同様に表示-非営利ライセンスに従います。

この記事は 2015年8月21日 に公開され、2015年8月21日 に最終更新されました。3698 日が経過しており、内容が古くなっている可能性があります。

ECMAScript6 学習メモ(1)- 変数宣言・文字列拡張・数値拡張
https://blog.kisnows.com/ja-JP/2015/08/21/learning-ecmascript6-one/
作者
Kisnows
公開日
2015-08-21
ライセンス
CC BY-NC-ND 4.0