盤點幾種資料型別的解構賦值細節

語言: CN / TW / HK

theme: smartblue

持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第6天,點選檢視活動詳情

解構賦值

何為解構賦值

  • 解構:可以在陣列或物件中的值分離出來
  • 賦值:將解構出來的資料對變數進行賦值

在ES5中的普通的變數賦值方法:

js var a = 1; var b = 2;

在ES6中的解構賦值方法,一句話解構賦值方法的過程即映象,兩邊的互為映象,相同位置變數和數值一一對應

js let [a,b] = [1,2] // 等價於上述

使用解構賦值方法可以將賦值變得靈活,下面將對解構賦值進行講解

陣列解構

巢狀解構

js允許陣列和物件的成員為陣列或物件,所有當陣列為巢狀陣列的時候,依舊可以對陣列進行解構賦值

js let [a,[b],c] = [1,[1,2],3] console.log(a,b,c) // 1 1 3

擴充套件運算子解構

在解構中可以使用...擴充套件運算子

js let [a,...b] = [1,2,3,4] console.log(a,b) // a = 1 b = [2,3,4]

不完全解構

兩邊不一定是完全匹配的,可以根據實際需要,對其進行解構賦值

js let [, , a] = [1,2,3] console.log(a) // 3

不成功的解構

當解構目標是其他型別的時候解構是不成功的

js let [a] = 1 console.log(a) // TypeError: 1 is not iterable

又或者當目標賦值變數與右側解構目標不匹配的時候,如下列,b的值為undefined,所以解構也是不成功的

js let [a,b] = [1] console.log(a,b) // 1 undefined

關於interator

在不成功的解構中如果的解構目標為一個數值,那麼丟擲的錯誤為1 is not iterable,翻譯一下:1是不可被可迭代的,下面瞭解一下interator即迭代器和解構賦值的關係。

js中內建了表示集合資料結構比如:Array,Object,兩者都含有interator,而undefined,null,NaN等等是不包含interator的,解構賦值無法作用於不含有interator的資料結構,而所有包含interator的資料解構都可以被解構賦值

帶有預設值的解構賦值

在不成功的解構中包含了不匹配的情況,而這種情況可以使用預設值來解決,無論是哪種型別的解構賦值都可以預先對變數進行賦值,避免不匹配而造成解構不成功的現象。

js let [a,b=2] = [1] console.log(a,b) // 1 2 let [c = 1] = [undefined] console.log(c) // 1

關於undefined的問題

當對變數賦為預設值,解構目標陣列內只含有一個undefined的情況下,變數最終會賦值為預設值,但是如果是NaNnull的情況下會是怎麼樣的。

js let [c = 1] = [NaN] console.log(c) // NaN let [c = 1] = [null] console.log(c) // null

出現上述情況的原因是因為在ES6中使用的是===來判斷一個位置是否含有值,造成了NaNnull不嚴格等於undefined的情況。

物件解構

與陣列解構的不同

因為陣列是有下標的,但是物件沒有,物件只能依靠屬性名,所以在物件的解構賦值時,變數名需要與解構物件中目標屬性名一致

js let {name} = {name:"豬痞惡霸"} console.log(name) // 豬痞惡霸

變數名與屬性名不一致

在重構前輩的程式碼的時候會遇到不可逆轉的情況,所以我們可以使用:來解決這個不可逆轉問題

js let {name:difname} = {name:"豬痞惡霸"} console.log(difname) // 豬痞惡霸

其實這裡是根據解構模式的本質來即模式匹配來實現的,使用name來匹配物件中的屬性來完成變數名的更改

多層巢狀物件的解構賦值

js let people = { name:"豬痞惡霸", like:{ community:"juejin", code:"js" } } let {name,like:{code}} = people console.log(name,code) // 豬痞惡霸 js

物件多層巢狀的話,可以根據一層一層的匹配來解構到所需的屬性,比如上面想要拿到code,所以先匹配到like物件,再對like物件進行解構賦值拿到code

模式問題

經過上面的例子清楚了多層物件的解構方法,通過模式匹配來拿到下一層屬性或者物件,那麼這裡的模式即like是不能夠拿到值得,我們列印一下會出現like is not defined的問題,這個是需要注意的。

字串解構

上面提到過可以被解構賦值的資料型別包括陣列和物件等含有迭代器的資料型別,而字串能夠像前兩者一樣被解構,是因為在進行解構賦值的時候,字串被轉化為了一個類似陣列的物件,一個類似陣列的物件會是什麼呢,下面來看一下。

js let str = "豬痞惡霸" let {1:first} = str console.log(first) // 痞

這是個很有意思的現象,通過模式匹配,使用1拿到痞,這個地方大致就能明白為什麼叫一個類似陣列的物件

除此之外還可以使用陣列形式的解構方式

js let str = "豬痞惡霸" let [a] = str console.log(a) // 豬

我們還可以通過物件解構形式拿到字串的屬性,比如說字串的長度

js let str = "豬痞惡霸" let {length} = str console.log(length) // 4

數值與布林值解構

數值和布林值能夠被解構賦值的原因是因為在解構之前可以將其轉化為物件

js let { toFixed:a} = 123 console.log(a) // toFixed() { [native code] }

可以直接解構出數值的一些方法和屬性比如上述解構出toFixed方法

利用原型鏈判斷

上面解構出toFixed方法,那麼這裡可以通過原型鏈來判斷兩者之間的異同

js console.log(a === Number.prototype.toFixed) // true

顯而易見,兩者是等價的,正如此說明在解構前數值會轉變為物件形式,包含了其屬性和通過原型得到的方法

布林值的解構與數值解構相同

函式引數解構

函式引數解構其實是函式與之前解構的結合,至少我是這麼認為的

js function add([x,y]) { return x+y } add([1,2]) // 3

但是這種解構方式又有什麼實際的作用,和普通的變數引數有什麼區別,請看下面的例子

js let arr = [[1,2],[2,3]] arr.map((item) => item[0]+item[1])

我們使用map遍歷一個巢狀陣列,然後再將其每個成員陣列內的成員相加,這是使用普通引數方法實現,那麼來使用解構賦值看一下。

js let arr = [[1,2],[2,3]] arr.map(([a,b]) => a+b)

這樣就很舒服,不需要複雜的下標來定位陣列成員,直接使用解構賦值剝離即可。

參考文獻

  • ES6標準入門第三版