系列文章 -- ES6筆記系列
解構賦值,即對某種結構進行解析,然后將解析出來的值賦值給相關的變量,常見的有數組、對象、字符串的解構賦值等
一、數組的解構賦值
function ids() { return [1, 2, 3]; } var [id1, id2, id3] = ids(); console.log(id1, id2, id3); // 1 2 3
如上,解析返回的數組,取出值並賦給相應的變量,這就是解構賦值
1. 還可以嵌套多層,只要相應的模式匹配了就能解析出來
var [a, [b, [c]]] = [1, [2, [3]]]; a // 1 b // 2 c // 3
2. 如若模式不匹配則報錯
var [a, [b, [c]]] = [1, [2, 3]]; // Uncaught TypeError: undefined is not a function a
其實,解構賦值內部的實現方式使用到了ES6的Iterator迭代器,通過層層遍歷,保證了相應值的獲取
3. 解構不成功,但模式匹配了,相應值為undefined
var [a, b] = [1]; a // 1 b // undefined
4. 不需要匹配的位置可以置空
var [, b] = [1, 2]; b // 2
5. 使用...這個擴展運算符,匹配余下的所以值,形成一個數組(匹配不上則為[]),這個符號內部也用到了迭代器Iterator
var [a, ...b] = [1, 2, 3]; a // 1 b // [2, 3] var [a, ...b] = [1]; a // 1 b // []
6. 可以設置默認值,當相應的值嚴格等於undefined時,默認值會生效
var [a, b = [2, 3]] = [1]; a // 1 b // [2, 3]
var [a, b = [2, 3]] = [1, undefined]; a // 1 b // [2, 3]
var [a, b = [2, 3]] = [1, null]; a // 1 b // null
7. 惰性求值,對於默認值中出現函數調用模式的,只有默認值生效,函數才會調用,如下,foo函數將不會被調用
function foo() { console.log('hit'); } var [str = foo()] = [1]; str // 1
8. 可以方便的進行變量值的交換
var x = 1, y = 2; [x, y] = [y, x]; x // 2 y // 1
二、對象的解構賦值
與數組類似,對象也可以進行解構賦值
var {name, agee} = { name: 'jack', age: 22,
}; name // jack agee // undefined
如上,對象的解構賦值要求屬性名稱匹配正確,agee不匹配則變成undefined
1. 不過我們可以自定義屬性名稱,但要注意的是被賦值的只是我們自定義的屬性名稱,匹配的模式(項)並未被賦值
var {name, id: ID} = { name: 'jack', id: 1 }; ID // 1 id // Uncaught ReferenceError: id is not defined
更復雜的如
var { a0: { b0: { c0 } } } = { a0: { b0: { c0: 'cc', d0: 'dd' } } }; a0 // Uncaught ReferenceError: a0 is not defined b0 // Uncaught ReferenceError: b0 is not defined c0 // cc
2. 類似於數組,也可使用默認值
var {a:b = 2} = {}; b // 2 var {a:b = 2} = { a: 1 }; b // 1
3. 因為數組實際上也是個對象,所以
var {0: one, 1: two} = [1, 2]; two // 2
4. 可以方便地將某個對象上的屬性方法一次性提取出來
var {map, slice} = Array.prototype; slice //
const {foo, bar} = require('./util');
5. 非聲明時的解構賦值
非聲明時,這里是指純粹的解構賦值,如下代碼
var a; {a} = { a: 1 }; // Uncaught SyntaxError: Unexpected token = a
以上代碼報錯了,但某些情況下我們還是需要直接賦值怎么辦?
大括號{位於行首,匹配了}之后JS引擎就會認為{a}是一個代碼塊,所以等號就出問題了,解決方式是在行首放個括號(,即外包裹一層括號()
var a; ({a} = { a: 1 }); a // 1
括號的出現,讓整個解構賦值的結構被看做一個代碼塊,而內部的{a}模式則可以正常匹配到
細心的盆友會注意到,右括號換個位置,報錯了
var a; ({a}) = { a: 1 }; // Uncaught SyntaxError: Unexpected token ( a
6. 其實,解構賦值中括號的使用還是有講究的
1) 不能使用括號的情況
1-1)變量聲明語句中,不能帶有括號
// 以下代碼都會報錯 var [(a)] = [1]; var {x: (c)} = {}; var ({x: c}) = {}; var {(x: c)} = {}; var {(x): c} = {}; var { o: ({ p: p }) } = { o: { p: 2 } };
1-2)函數參數中,模式不能帶有括號
// 報錯 function f([(z)]) { return z; } f([1])
1-3)賦值語句中,不能將整個模式,或嵌套模式中的一層,放在括號之中
var a; ({a}) = { a: 1 }; // Uncaught SyntaxError: Unexpected token ( a
2)可以使用括號的情況
可以使用括號的情況很好記,只有一種:賦值語句的非模式部分,可以使用括號
// 都正確 [(b)] = [3]; ({ p: (d) } = {}); [(b)] = ([3]);
三、字符串的解構賦值
字符串也可進行解構賦值,因為此時的字符串被轉換成了類數組的對象,模式能夠匹配起來,如
var [a, b] = 'str'; a // s b // t var {0:a, 1:b, length:len} = 'str'; a // s b // t len // 3
四、其他類型的解構賦值
1. 解構賦值的規則是,只要等號右邊的值不是對象,就先嘗試將其轉為對象。如果轉換之后的對象或原對象擁有Iterator接口,則可以進行解構賦值,否則會報錯。
var {toString: s} = 1; s // var {toString: s} = true; s //
以上的數組和布爾值會轉換成對象,toString模式匹配上了對象的toString屬性,所以解構成功,而null或undefined卻不能轉換成此類對象,所以報錯
var {toString: s} = null; s // Uncaught TypeError: Cannot match against 'undefined' or 'null'.
ES6引入了Iterator迭代器,集合Set或Generator生成器函數等都部署了這個Iterator接口,所以也可以用來進行解構賦值
2. 比如Set的解構賦值
var [a, b, c] = new Set([1, 2, 3]); a // 1 b // 2 c // 3
3. 函數參數的解構賦值
function calc([a, b, c = 10]) { console.log(a + b + c); // 13 } calc([1, 2]);