メインコンテンツへ移動

destructuring(分割代入)_ES6 ノート 5

無料2016-04-24#JS#es6解构#js解构#js destructuring#es6析构#js析构

es6 の基本的な構文糖衣で、シンプルで使いやすい

一.目標

オブジェクトまたは配列から値を取得し、他の変数に代入するには、以前はこのようにする必要がありました:

var arr = [1, 2, 3, 4];
var first = arr[0];
var senond = arr[1];
var third = arr[3];

配列を分解して要素値を取得し、代入します。上記のプロセスは:分解 - 代入です

ES6 は新しい概念を提案しました:destructuring(分割代入)、上記のプロセスをより良い可読性を持たせ、「ハードコーディング」スタイルのコードを回避できます

二.iterable 分割代入

var/let/const [var1, var2...] = iterable 構文は、変数宣言と同時に配列/イテレータ分割代入を行うことを表します

分割される値は iterable でなければなりません。ジェネレーター構文を通じてカスタムオブジェクトを簡単に iterable にできます([黯羽軽揚:for…of ループ_ES6 ノート 1](/articles/for-of 循环-es6 笔记 1/#articleHeader5) を参照)。iterable 分割代入の特徴は以下の通り:

  • 任意の深さのネスト配列に対して分割代入可能

  • 空位を残して特定の要素をスキップ可能

  • 可変長引数(...var 構文、詳細は [黯羽軽揚:デフォルトパラメータと可変長引数_ES6 ノート 4](/articles/默认参数和不定参数-es6 笔记 4/) を参照)を使用して残りのすべての要素をキャプチャ可能

例えば:

// 配列
var [[first, [second]], third] = [[1, [2]], 4];
console.log(`first = ${first}`);    // 1
console.log(`second = ${second}`);  // 2
console.log(`third = ${third}`);    // 4

// iterable
var iter = (function*(start) {
    while (true) {
        yield start++;
    }
})(0);
var [v1, v2, v3, v4] = iter;
console.log(`v1 = ${v1}`);  // 0
console.log(`v2 = ${v2}`);  // 1
console.log(`v3 = ${v3}`);  // 2
console.log(`v4 = ${v4}`);  // 3

// 要素をスキップ、残りの要素をキャプチャ
var arr = [1, 2, 3, 4];
var [, sec, ...aRest] = arr;
console.log(`sec = ${sec}`);        // 2
console.log(`aRest = ${aRest}`);    // [3, 4]

「ハードコーディング」スタイルのコードはすべてなくなり、しかも分割代入はより明確で直感的です(左右対応)

三.オブジェクト分割代入

var/let/const {key: varName, ...} = obj 構文はオブジェクト分割代入を表します

特に注意代入順序は左から右へ です。実際の効果は:varName = obj[key] です

分割される値は必ず オブジェクトに強制変換できる必要があります。そのため undefined/null を分割代入すると TypeError が報告されます

オブジェクト分割代入の特徴は以下の通り:

  • 変数名とオブジェクトプロパティ名が一致する場合は簡略化可能

  • 特定のプロパティ名に対してのみ代入可能(空位を残してスキップする必要はありません)

  • 複雑なネスト(オブジェクト + 配列)をサポート

例えば:

// obj
var obj = {name: 'aae', age: 12, sex: 'F'};
// 特定のプロパティ名に対してのみ代入
var {name: mName, sex: mSex} = obj;
console.log(`mName = ${mName}`);    // mName = aae
console.log(`mSex = ${mSex}`);      // mSex = F
// 変数名とプロパティ名が同じ場合簡略化
var {name, sex} = obj;
console.log(`name = ${name}`);      // name = aae
console.log(`sex = ${sex}`);        // sex = F

注意、分割代入の左側に var/let/const がない場合(つまり変数宣言を忘れたか、変数がすでにあり再宣言したくない)、構文エラーが発生します。以下の通り:

// var key;

{key} = {key: 'val'};
// 报错:Uncaught SyntaxError: Unexpected token =(…)

代入記号の左側の {key} はブロック({})として解析されるためです。この動作を回避する方案は分割代入に丸括弧を付ける ことです。例えば:

({key} = {key: 'val'});
console.log(`key = ${key}`);    // key = val

丸括弧 inside はすべて式であり、{key} は誤ってブロックとして解析されません

四.分割代入同時にデフォルト値を設定

構文はデフォルトパラメータ構文と類似です。例えば:

// default val
var [val = 'default val'] = [];
var {key: val = 'default val'} = {};
// 属性名が同じ場合簡略化可能
// FF43,45 都不支持,thinkjs,Chrome50 支持
// var {val = 'default val'} = {};
console.log(`val = ${val}`);

1 つの文でデフォルト値を設定し、分割代入も行いますが、構文はより複雑な場合で読みづらいです(例えば上記の var {key: val = 'default val'} = {};

五.まとめ

この特性も錦上添花的なもので、「ハードコーディング」スタイルのコードを減少し、その可読性を強化します

用途:

  • 関数定義中のオブジェクト��ラメータ、例えば function ajax(config)function ajax({url, data, callback}) に変更後 API 可読性がより良く、デフォルト値と配合して非常に便利です(var attr = config.attr || defultVal; のような操作を回避)

  • イテレータと配合し、map を遍历するのに便利です([key, val] 遍历鍵値対、[key] 遍历鍵集、[, val] 遍历値集)

  • 関数が複数の値を返すことを実装(配列を返し、戻り値を受け取る時に各変数に分割代入)

  • 一部の CommonJS モジュールをインポートし、必要な部分のみ分割代入。ES6 モジュールの import は類似の機能をサポート

例えば:

// use
// 1
function ajax({url, data, callback}) {
    console.log(`ajax(${url}, ${data}, ${callback})`);
}
ajax({url: 'www.xxx.xx', data: 'data'});
// log print: ajax(www.xxx.xx, data, undefined)

// 2
for (var [key, val] of new Map([['name', 'eea'], ['age', 12]])) {
    console.log(`key = ${key}, val = ${val}`);
}
// log print: key = name, val = eea
//            key = age, val = 12

// 3
var [res1, res2] = (function() {
    return [1, {a: 1}];
})();
console.log(`res1 = ${res1}, res2 = ${res2}`);
// res1 = 1, res2 = [object Object]

参考資料

  • 《ES6 in Depth》:InfoQ 中国語駅が提供する無料電子書籍

コメント

コメントはまだありません

コメントを書く