深入ES6 三 變數的解構賦值
解構賦值指的是按照一定規則,直接從陣列和物件中提取值,對變數進行賦值。這章主要包括:
- 陣列的解構賦值
- 物件的解構賦值
- 巢狀與匹配模式
- 應用
基本用法
解構賦值的本質是模式匹配,只要左右兩邊的模式相同,左邊的變數就會被賦予對應的值。如果解構不成功,則返回undefined。
let [d,b,c] = [1,2,3]; // => d=1;b=2;c=3
let [[f]] = [[1]]; // =>f=1
let [e,...tail] = [1,2,3,4]; // =>e=1;tail = [2,3,4]
這裡let [a, b, c]
表示定義了用於陣列解構的三個變數a, b, c。解構採取貪婪匹配原則,儘量解構更多的資料,並且即使模式不是完全匹配,也能部分解構成功。上面的rest(...)運算子會收錄匹配到的其餘資料進一個陣列,但其必須出現在末尾,否則會報錯。
注意:採用結構賦值的寫法,變數的宣告和賦值是一體的,對於let和const而言,變數不得重新宣告,否則會報錯。
let [a, b, c] = [1, 2, 3];
let a = 10; // 報錯,因為a已經宣告過了
再介紹一個乍一眼看上去容易出錯的例子:
let [a, [b], c] = [1, [2, 3], 4]; // b=>2
// 如果想讓b的值解構後為[2,3],需要寫成
let [a,[...b],c] = [1, [2, 3], 4];
// 或者最簡單的
let [a, b, c] = [1,[2,3],4]
右值的要求
在進行對陣列的解構賦值時,等號右邊必須是可遍歷的解構,比如說陣列,Set集合,甚至Generator物件(會在面的章節介紹)。否則會報錯。
字串在解構時會被轉化成一個類似陣列的物件,因此可以用於陣列的解構賦值
let [a, b, c] = 'hello' // => a=h; b=e; c=l
字串擁有length屬性,我們也可以使用物件的解構賦值來獲得之,此時字串hello會被包裝成一個物件:
let {length} = 'hello'
預設值
可以指定解構賦值時的預設值,當右值陣列成員嚴格等於undefined時,預設值才會生效。
let [a = 'hello'] = []; //a='hello'
let [a = 'hello'] = [null]; //a=null
如果預設值是表示式,它的求值方式是惰性的,只有需要使用預設值的時候,才進行計算
let foo = () => {
console.log('fooing');
return 'foo'
};
let [b = foo()] = []; // 會執行foo函式
let [b = foo()] = ['bar']; // 不會執行foo函式
預設值也可以引用解構變數的其它值,但引用的值必須在引用之前被宣告
let [x, y = x] = [1]
基本用法
let {c, d} = {c:'c, e:'e', d:'d'};
c //=> 'c'
d // => 'd'
與陣列解構的一個不同之處在於物件解構把[]換成了{}, let {c, d}
定義了兩個全域性變數:c和d。此外,物件解構賦值是和物件屬性的定義順序無關的,只要名稱能夠匹配,即左邊的變數名與右邊的屬性名相同,就可以取得正確的值。為了告訴你們這點,我特意把e安排到了d前面。
很多時候我們不希望我們的區域性變數名和屬性名完全相同,那麼可以採取下面的辦法:
let {foo:baz} = {foo:'foo',bar:'bar'}; // => baz=foo
格式是:
{屬性名:變數名... ...}={屬性名:值...}
也就是說只需要在屬性名後面加":希望的變數名"就可以了。
那麼,你肯定能夠想到,我們開始時寫的這種形式:
let {c, d} = {c:'c, e:'e' ,d:'d'};
其實是下面形式的簡寫,因為它們的屬性名和變數名是相同的。真正被賦值的其實是後者:
let {c:c, d:d} = {c:'c, e:'e', d:'d'};
使用()告訴引擎我在用解構賦值
如果一個已經宣告的變數進行解構賦值,大概會像下面這樣:
let foo;
{foo} = {foo:'foo'} // 報錯
這是因為大括號寫在了首行,JS引擎會把它當成一個程式碼塊,解決辦法很簡單,加上()就可以了:
({foo} = {foo:'foo'})
注意,除了這裡以及函式表示式呼叫的時候可能要用到(),我們使用解構賦值的時候儘量不要使用(),因為它幾乎沒有用處,還容易導致各種錯誤出現
預設值
前面提到過的
let {foo:foo,bar:baz} = {foo:'foo',bar:'bar'}
在進行解構賦值時,實際上是先透過左邊的foo,bar屬性名去到右邊匹配屬性,然後把匹配到的屬性的值賦給左邊的:後的變數名。那麼你就不難想到,物件解構可以像下面這樣設定預設值:
let {foo='bbb',bar:baz='aaa'} = {foo:'foo',bar:'bar'}
上面的程式碼foo代表屬性名和變數名相同的情況,baz代表不同的情況。
右值的要求
使用物件解構賦值時,右值可以是簡單資料型別布林、字串或者數字。解構時,會先將其轉化為物件,再進行解構。
右值不得是不能轉成物件的null或undefined,因為它們沒有對應的包裝類。
物件巢狀的陷阱
如果在解構模式中左值是物件巢狀物件的形式,且外部物件屬性沒有正確匹配,則在匹配該物件的內部屬性時將會報錯:
var {foo:{bar}} = {baz:'baz'}
上面的程式碼中,等號左邊物件的foo屬性無法正確匹配,所以值為undefined。當繼續匹配其中的bar屬性時,就會報錯,因為我們不能從undefined中取子屬性。
解構賦值本身非常靈活,所以可以進行匹配模式的巢狀:
let {arr:[x,{prop}]} = {arr:[1,{prop:2}]};
console.log(x); // =>1
console.log(prop); // =>2
console.log(arr); // 報錯,未定義
上面程式碼中的arr是匹配模式的一部分,所以不會被賦值。
這裡舉幾個解構賦值非常常見的應用:
交換兩個變數的值
[foo,bar] = [bar,foo];
定義函式的引數
var foo = ([x, y])=>x+y;
foo([1,2]) // =>3
或者以物件的形式,這樣可以最佳化以配置物件形式編寫函式引數方式的程式碼
var bar = ({x, y, z=5}) => x-y+z
bar({x:1, y:2}) // => 4
但需要注意的是,不要把解構賦值預設引數與ES6函式本身預設引數的特性相混淆。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2144/viewspace-2798648/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- ES6 - 變數的解構賦值解析變數賦值
- ES6之變數的解構賦值變數賦值
- ES6 -- 變數的解構賦值的用途變數賦值
- ES6:變數的結構賦值變數賦值
- ES6入門之變數的解構賦值變數賦值
- 變數的解構賦值變數賦值
- ES6標準入門之變數的解構賦值變數賦值
- ES6解構賦值賦值
- ES6 解構賦值賦值
- ES6系列入門學習記錄:變數的解構賦值變數賦值
- ES6中的解構賦值賦值
- ES6學習-4 解構賦值(1)陣列的解構賦值賦值陣列
- ES6之解構賦值賦值
- ES6 解構賦值+改名賦值
- ECMAScript 6入門 - 變數的解構賦值變數賦值
- ES6學習筆記二(變數結構賦值)筆記變數賦值
- JS中的變數賦值深入理解JS變數賦值
- ES6學習解構賦值賦值
- ES6基礎知識——let、const關鍵字和變數的解構賦值變數賦值
- ES6 - let與const,解構賦值賦值
- 【ES6基礎】解構賦值(destructuring assignment)賦值Struct
- ES6變數解構變數
- Javascript 解構賦值,將屬性/值從物件/陣列中取出,賦值給其他變數JavaScript賦值物件陣列變數
- 淺談Python變數賦值的三種方法!Python變數賦值
- 變數的賦值 指標間接賦值變數賦值指標
- ES6小技巧 - 使用解構賦值設定函式引數預設值賦值函式
- 基礎知識梳理~ES6 解構賦值賦值
- php之普通變數賦值、物件賦值、引用賦值的區別PHP變數賦值物件
- ES6 變數宣告與賦值:值傳遞、淺拷貝與深拷貝詳解變數賦值
- 解構賦值賦值
- ES6學習筆記(五)【解構賦值,Iterator】筆記賦值
- JavaScript函式引數解構賦值JavaScript函式賦值
- 【系統學習ES6】第二節:解構賦值賦值
- JS解構賦值JS賦值
- JavaScript解構賦值的用途JavaScript賦值
- shell 變數賦值問題變數賦值
- shell變數命名與賦值變數賦值
- ES6新特性總結之解構賦值和字串模板賦值字串