【系統學習ES6】第二節:解構賦值

Lemoncool發表於2022-01-13

【系統學習ES6】

本專題旨在對ES6的常用技術點進行系統性梳理,幫助大家對其有更好的掌握,希望大家有所收穫。

 

ES6允許按照一定模式,從陣列和物件中提取值,對變數進行賦值,這被稱為解構。解構是一種打破資料結構,將其拆分為更小部分的過程。

為何使用解構

傳統寫法中,從陣列或物件中提取特定資料賦值給變數,編寫了很多結構相同,變數不同的程式碼,例如:

let option = {
   name:'foo',
   type:'string'
};
let name = option.name;
let type = option.type;

以上程式碼的作用是,從option物件中提取name和type兩個屬性,賦值給變數name和type。此時只有兩個變數,想象一下,如果有更多變數,那就要依次追加多句賦值。如果其中包含巢狀結構,那就要深入讀取層級,才能找到目標變數。

也許是為了解決這種困擾,所以ES6為物件和陣列新增了解構功能,在合適的場景下運用,大大減少程式碼量,提高工作效率。

解構成功的前提,是左右兩側型別一致,即:如果是物件解構,左側被賦值變數必須包裝在{ }內,同理,陣列解構,左側必須是[ ]。

物件解構

上文強調過:物件的解構,左側必須是{ }。只要左側的變數在右側物件中有,即使位置不同,也可被成功賦值,但如果變數在右側沒有與之對應的屬性,則會被賦值為undefined。

let option = { name:'foo', type:'string' };
let { name, type } = option;
// let { type, name } = option; // 此句與上句效果相同
console.log(name);  // 'foo'
console.log(type);  // 'string'
 
let { age } = option;
console.log(age);  // undefined
 
let { name } = option;
console.log(name); // 'foo'

注意:物件解構前,必須提供初始值(即右側的物件)。如果右側沒有值,程式會拋異常。

let { name };  // Uncaught SyntaxError:

為非同名變數賦值

如果變數名與物件屬性名不一致,可以通過解構對變數賦值麼?ES6的另一個擴充語法可以幫助我們。

let option = { name:'foo', type:'string' };
let { name: attrName, type: attrType} = option;
console.log(attrName); // 'foo'
console.log(attrType);  // 'string'

這實際上說明,物件的解構賦值是下面形式的簡寫:

let { name: attrName, type: attrType} = { name:'foo', type:'string' };

也就是說,物件的解構賦值的內部機制,是先找到同名屬性,然後再賦給對應的變數。真正被賦值的是後者,而不是前者。

巢狀賦值

可以單層解構賦值,就支援巢狀賦值。前提是左右兩邊形式一致。

let option = {
  name: 'foo',
  type: 'string',
  start: { row: 1, col: 0 }
};
let { start: { row } } = option;
console.log(row); // 1

陣列解構

陣列的解構與物件有一個重要的不同。物件的解構按屬性名決定的,左右兩側變數位置可以不一致,但變數必須與屬性同名,才能取到正確的值。

陣列的元素是按順序排列的,變數的取值由它的位置決定。只要等號兩邊型別相同(都是陣列格式),左側變數會按照位置關係,被賦予右側陣列的同的值。在這個過程中,右側陣列本身不會發生變化。

let [name, type] = ['foo','string'];
console.log(name);  // 'foo'
console.log(type); // 'string'

巢狀賦值

let [a, [b, c] = [1, [2, 3]];
console.log(name); // 1
console.log(type); // 2
console.log(height); // 3

如果左右形式不一致,可能會直接報錯:

let [a] = 1; // Uncaught TypeError: 1 is not iterable

如果右側陣列元素數量比左側變數多,可以解構成功。屬於不完全匹配。

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

如果右側陣列元素數量比左側變數少,這種情況屬於解構失敗,解構失敗的變數會被賦值為undefined。

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

此時,b是undefined理解,那c為什麼是陣列?這不是解構的鍋,相關知識點,後面會討論到。

預設值設定

不管是陣列還是物件,解構賦值都允許指定預設值。只有當右側相應屬性或位置的值全等(===)undefined,預設值才會生效。

陣列:

let [a = 1] = [];  // a=1
let [a, b = 2] = [1]; // a=1, b=2
let [a, b = 2] = [1, undefined]; // a=1, b=2
let [a, b = 2] = [1, null]; // a=1, b=null
let [a, b = 2] = [1, ""]; // a=1, b=""

物件:

let { name, type = 'string' } = { name: 'foo'}; 
// name:'foo' type:'string'
let { name, type = 'string' } = { name: 'foo', type: undefined}; 
// name:'foo' type:'string'
let { name, type = 'string' } = { name: 'foo', type: null}; 
// name:'foo' type:'null'
let { name, type = 'string' } = { name: 'foo', type: ''};
// name:'foo' type:''

圓括號的妙用

(1)如果要將一個已經宣告的變數用於解構賦值,要注意一下寫法。

let name = 'bar';
{ name } = { name: 'foo' };
console.log(name); // SyntaxError: syntax error

上面程式碼會報錯,因為 JavaScript 引擎會將{name}理解成一個程式碼塊,從而發生語法錯誤。只有不將大括號寫在行首,才能解決這個問題。於是圓括號來了。陣列同理。

let name = 'bar';
({ name } = { name: 'foo' });
console.log(name); // 'foo'

字串解構

字串也可以解構,這是因為,此時字串被轉換成了一個類似陣列的物件。

const [a,b,c,d,e]="lemoncool";
console.log(a); // l
console.log(b); // e
console.log(c); // m
console.log(d); // 0
console.log(e); // n
.....

混合解構

討論完物件和陣列的解構,其實可以基於二者來創造更復雜的表示式解構。比如json中,陣列和物件混雜,此時想解析到某個資訊。是否可以實現呢?答案是肯定的,前提是格式要對應正確,篇幅有限,此處不再舉例。

解構實用場景

解構,除了基礎的變數賦值外,用途還有很多。

1、交換變數的值

let x = 1;
let y = 2;
[x, y] = [y, x];

上面程式碼交換變數x和y的值,這樣的寫法不僅簡潔,而且易讀,語義非常清晰。

2、返回多個值

函式只能返回一個值,如果要返回多個值,只能將它們放在陣列或物件裡返回。有了解構賦值,取出這些值就非常方便。

function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();

3.引入腳手架中的指定方法

腳手架不想整體引入,可以指定引入某些方法。

import { cloneDeep, random } from 'lodash'; 

 

到此,變數解構的使用方法及注意事項已梳理完畢。

下一節我們會一起討論【擴充運算子和res運算子】,感謝大家支援,希望大家在每一節中都有所得。

 

前端便利貼 公棕號【前端便利貼】記錄著一個程式媛的所見所得所想,分享日常技術筆記,內容覆蓋了閱讀、技術和個人思考~,關注公棕號更早獲取更多文章。

覺得有用的話,小手點點【推薦】再走吖~~【系統學習ES6】第二節:解構賦值

相關文章