1. 數組的解構賦值
[ 基本用法 ]
按照一定的模式從數組或者對象中取值,對變量進行賦值的過程稱為解構。
以前,為變量賦值只能直接指定值:
而ES 6 允許寫成下面這樣:
上面的代碼表示,可以從數組中取值,按照位置的對應關系對變量賦值。
[ 默認值 ]
解構賦值允許使用默認值。
ES6內部使用嚴格相等運算符(===)判斷一個位置是否有值。所以,如果一個數組成員不嚴格等於undefined,默認值是不會生效的。
上述代碼中,一個數組成員是null,因此默認值不生效。因為null不嚴格等於undefined。
如果默認值是一個表達式,那么這個表達式是惰性求值的,即只有在用到的時候才會求值。
2.對象的解構賦值
對象的解構賦值與數組有一個不同,數組的元素是按次序排列的,變量的取值由它的位置決定;而對象的屬性沒有次序,變量必須與屬性同名,才能取到正確的值。
上面代碼中,變量沒有對應的同名屬性,導致取不到值,最后等於undefined。
實際上,對象的解構賦值是以下形式的簡寫:
var { foo: foo, baz: baz } = { foo:"aaa", baz:"bbb" }
也就是說,對象的解構賦值的內部機制,是先找到同名屬性,然后再賦給對應的變量。真正被賦值的是后者,而不是前者。
采用這種寫法時,變量的聲明和賦值是一體的。對於let和const而言,變量不能重新聲明,所以一旦賦值的變量以前聲明過,就會報錯。
上述代碼沒有第二個let命令就不會報錯:
和數組一樣,解構也可以用於嵌套結構的對象。
對象的解構也可以指定默認值。
默認值生效的條件是,對象的屬性值嚴格等於undefined。
如果解構模式是嵌套的對象,而且子對象所在的父屬性不存在,那么將會報錯。
這時foo的值是undefined所以再取子對象會報錯。
3.字符串的解構賦值
字符串的解構賦值機制是將字符串轉換成一個類似數組的對象:
類似數組的對象都有length屬性,因此還可以對這個屬性解構賦值:
4.數值和布爾值的解構賦值
解構賦值的規則是:只要等號右邊的值不是對象,就先將其轉為對象。
5.函數參數的解構賦值
上面代碼中,函數add的參數實際上不是一個數組,而是通過解構得到的變量x和y。
函數參數的解構也可以使用默認值。
上面的代碼中,函數move的參數是一個對象,通過對這個對象進行解構,得到變量x和y的值。如果解構失敗,則x和y等於默認值。
注意:下面的寫法會得到不一樣的結果。
6.圓括號問題
解構賦值雖然很方便,但是解析並不容易。對於編譯器來說,一個式子到底是模式還是表達式,沒有辦法從一開始就知道,必須解析到(或解析不到)等號才能知道。由此帶來的問題是,模式中出現圓括號怎么處理,ES6的規則是,只要有可能導致解構歧義,就不得使用圓括號。
[ 不能使用圓括號的情況 ]
以下3種解構賦值不得使用圓括號:
- 變量聲明語句中,模式不能帶有圓括號。
上面3條語句都會報錯,因為它們都是變量聲明語句,模式不能使用圓括號。
- 函數參數中,模式不能帶有圓括號。
函數參數也屬於變量聲明,因此不能帶有圓括號。
- 不能將整個模式或嵌套模式中的一層放在圓括號中。
上面的代碼將整個模式放在了圓括號中,導致報錯。
上面的代碼將嵌套模式的一層放在了圓括號中,導致報錯。
[ 可以使用圓括號的情況 ]
可以使用圓括號的情況只有一種:賦值語句的非模式部分可以使用圓括號
7.用途
[ 交換變量的值 ]
[x, y] = [y, x]
上面的代碼交換了x和y的值,這樣的寫法不僅簡潔,而且易讀,語義非常清晰。
[ 從函數返回多個值 ]
函數只能返回一個值,如果要返回多個值,只能將其放在數組或對象中返回。有了解構賦值,取出這些值就非常方便。
// 返回一個數組
// 返回一個對象
[ 函數參數的定義 ]
解構賦值可以方便地將一組參數與變量名對應起來。
// 參數是一組有次序的值 function f([x,y,z]) {...} f([1,2,3])
// 參數是一組無次序的值 function f([x,y,z]) {...} f({z: 3, y: 2, x: 1})
[ 提取JSON數據 ]
解構賦值對提取JSON對象中的數據尤其有用。
[ 函數參數的默認值 ]
jQuery.ajax = function (url,{ async = true, beforeSend = function(){}, cache = true, complete = function(){}, crossDomain = false, global = true, // ... more config }){ // ... do stuff }
指定參數的默認值,就避免了在函數體內部再寫var foo = config.foo || 'default foo';這樣的語句。
[ 遍歷Map解構 ]
任何部署了Iterator接口的對象,都可以用for...of循環遍歷。Map結構原聲支持Iterator接口,配合變量的解構賦值,獲取鍵名和鍵值就非常方便。
如果只是想獲取鍵名,或者只是想獲取鍵值,可以寫成下面這樣:
// 獲取鍵名 for (let [key] of map) { // ... } // 獲取鍵值 for (let [value] of map) { // ... }
[ 輸入模塊的指定方法 ]
加載模塊時,往往需要指定輸入哪些方法。解構賦值使得輸入語句非常清晰。
const { SourceMapConsumer, SourceNode} = require("source-map")