寫這篇文章之前早已有“提筆畫西遊”的衝動,苦苦翻閱很多資料終於理解了神祕感十足的解構賦值,可奈何最近忙於工作上的事情擠不出時間更新博客。話不多說、先請JS祖師爺 - Douglas Crockford!
解構賦值:ES6 允許按照一定模式,從數組和對象中提取值,對變量進行賦值,這被稱爲解構。
1、數組解構賦值:
通常定義變量並賦值的時候只能一個一個定義之後再賦值,例如:
let name = 'Destructuring'
let age = 46
let sex = '男'
而ES6允許我們藉助數組的解構賦值來這樣寫:
let [name, age, sex] = ['Destructuring——2', 46, '男']
由上述代碼可知,結構賦值本質上是根據左邊數組的索引來尋找右邊數組對應的索引、之後而賦值。
嵌套數組的解構:
let [name, [hobby], car] = ['馬雲', ['賺錢'], '奔馳-邁巴赫']
console.log(name, hobby, car) //馬雲 賺錢 奔馳-邁巴赫
空位數組的解構:如果解構不成功,變量的值就等於undefined
。
let [, , , age, name, hobby] = [15, 23, 32, 46]
console.log(age, name, hobby) //46 undefined undefined
剩餘參數解構:注意剩餘參數的返回值是真數組,arguments是僞數組。
let [name, ...car] = ['馬雲', '奔馳-邁巴赫', '保時捷-911', '蘭博基尼1-大牛']
console.log(name, car) //馬雲 ["奔馳-邁巴赫", "保時捷-911", "蘭博基尼1-大牛"]
解構失敗:若被解構的值不是可遍歷的結構,則會解構失敗導致報錯。
// 報錯
let [name] = 1;
let [name] = false;
let [name] = NaN;
let [name] = undefined;
let [name] = null;
let [name] = {};
默認參數:解構賦值時允許像函數傳參那樣攜帶默認參數。
let [name = '馬雲', sex = '女'] = [, '男']
console.log(name, sex) //馬雲 男
解構順序是先判斷等號右側數組裏面是否可以解析成功,判斷解析成功的標準有兩個:一是等號右邊必須是可遍歷的結構、二是判斷當前被解構的值是否恆等於undefined,於是就會出現下面有趣的事情:
let [name = '馬雲'] = [undefined]
name '馬雲'
let [name = '馬雲'] = [null]
name null
看到這裏,我猜你一定會在控制檯去判斷undefined == null 結果返回true,既然undefined == null 爲什麼undefined啓用了默認值,而null卻沒有啓用默認值?
原因就是 undefined == null 返回true使用的是 ==(普等) 、undefined === null返回false 而結構賦值時使用的就是 ===(恆等),既然undefined === null 爲false ,那麼就認爲null可以解構成功,所以結果name = null。
默認參數可以是一個函數?這就很有趣了,因爲可以通過傳遞函數得出擁有默認值時 先賦值默認值再去解構?還是先解構如果不成功再去賦值默認值? 或 先解構、如果成功就解構下一個?這是一個值得深思的執行順序問題,因爲我們無法從默認值是其他數據類型時判斷這個問題:
function Fn() {
console.log('函數被調用')
return '默認值'
}
let [Str = Fn()] = ['解構賦值']
上述代碼可以正常解構賦值,運行時 若Fn函數打印了‘函數被調用’,那執行順序就是先使用默認值、再去解構;
若Fn函數沒有打印‘函數被調用’、說明函數未被調用,直接解構成功,執行順序就是先解構 判斷是否成功、若失敗再去賦默認值;
到現在已經很明確了,解構賦值的執行順序是 先解構、若成功 則不會再去判斷默認值。失敗 纔會去啓用默認值。
2、對象解構賦值:
let { Car, Color , width } = { Color: 'black', Car: '奔馳'}
console.log(Car,Color, width ) //奔馳 black undefined
對象結構賦值與數組解構賦值的區別在於:數組結構時是按照索引找對應值、而對象則是根據鍵名尋找對應值,且與次序無關,若鍵不存在則賦值爲undefined。
我們可以借用對象解構賦值很輕鬆的實現將window對象上的方法賦值到對應的變量上面,例如console.log()
const { log } = console
log('hello word') //hello word
是不是以後開發的時候再也不擔心拼錯console.log了?仔細想想爲什麼會這樣?
解構賦值時、等號右側是一個對象、也可以是一個對象的鍵名。window對象上的console對象裏面包含log、error等打印日誌的方法,剛好我們需要解構的鍵名是log,此時就是把console上的log方法單獨提列出來賦值給log這個變量,就是這麼 so easy!!
對象解構的難點:
引導:很多時候我們會把一個變量 轉換爲對象的形式,例如:
let lastName = "張三"
let obj = { name : lastName }
console.log(obj) //{name: "張三"}
ES6《屬性的簡潔表示法》允許在大括號裏面,直接寫入變量和函數,作爲對象的屬性和方法,根據ES6這個特效將一個變量轉換爲對象。
問題:如果變量名與屬性名不一致,必須寫成下面這樣。
let { person : lastName } = { person : '馬雲' }
console.log(lastName) //馬雲
console.log(person) //person is not defined
上述代碼左邊的person找到了右邊person的值,但是真正賦值的時候卻不是賦值給了自己,而是賦給lastName,也就是說對象的解構賦值機制是先根據等號左側的屬性名、找到右側的同名屬性,之後再賦值給對應的變量,即lastName這個變量。
未完....