跳到主要內容
黯羽輕揚每天積累一點點

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

圓括號裡面的都是表示式,{key} 不會被誤解析為塊

##四。解構同時設定預設值

語法與預設引數語法類似,例如:

// default val
var [val = 'default val'] = [];
var {key: val = 'default val'} = {};
// 屬性名相同時可以簡寫為
// FF43,45 都不支援,thinkjs,Chrome50 支援
// var {val = 'default val'} = {};
console.log(`val = ${val}`);

一條語句既設定預設值,又解構賦值,但語法在更複雜的情況下語法有些難讀(例如上面的 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 中文站提供的免費電子書

評論

暫無評論,快來發表你的看法吧

提交評論