Web 基礎系列之 ES6

語言: CN / TW / HK

導讀:平時我們在開發中,為了趕時間儘快完成專案而習慣採用我們之前囉嗦的寫法來實現某些功能,沒有去思考有沒有更好的實現方式,我們彷彿真的成了一個沒有靈魂的機器。

有時候你是不是會聽到:

“因為時間太緊了,先把功能實現,後面有時間再優化程式碼”

這種情況下往往就沒有下文了,正所謂:

“Later is Never”

長年累月就會發現專案中的程式碼寫得很“糙”。

本文旨在使用 ES6 語法優化程式碼中的一些小功能點,ES6 中的一些新特性確實能給我們提供一些很好的幫助,使我們的程式碼更簡潔和易讀。相信大家對 ES6 並不陌生,官方文件都看了至少一遍了吧,下面就看一下如何使用 ES6 將我們的程式碼變得更美觀。

01

物件取值

 const obj= {    
firstName: "an",
lastName: "xiu",
gender: "female",
age: 18
}

ES5 寫法:

 const firstName = obj.firstName 
const lastName = obj.lastName
const gender = obj.gender
const age = obj.age

這樣一個個定義變數和取值有點繁瑣,我們可以使用 ES6 物件的解構賦值嘗試一下。

ES6 寫法:

const { firstName, lastName, gender, age } = obj;

一行程式碼搞定!

如果我們想要定義的變數和物件中的欄位名不同,我們還可以這樣做。

const { firstName: stuFirstName, lastName: stuLastName, gender: stuGender, age: StuAge } = obj;   console.log(stuFirstName) // 1

這裡需要注意的是:

const { firstName: stuFirstName } = obj

其中 stuFirstName 為我們新定義的變數, firstName 為從物件中取出的變數,順序與我們平時賦值的寫法正好相反,我們可以將其理解為: a as a1 給予 a 一個 a1 的別稱。

02

數組合並

const arr1 = [1,2,3];
const arr2 = [1,4,5];

ES5 寫法:

const arr = arr1.concat(arr2); // [1,2,3,1,4,5]

使用 concat() 可以將兩個陣列拼接成一個新陣列,但是我們漏掉了一個點,生成的新陣列包含重複的元素,我們並沒有對陣列進行去重操作。

ES6 寫法:

ES6提供了新的資料結構Set,它類似於陣列,但是成員的值是唯一的,沒有重複的值。

基於以上合併陣列的操作,對陣列進行去重。

const newArr = [...new Set(arr)]; 

const newArr = Array.from(new Set(arr)) // [1,2,3,4,5]

03

if 條件判斷

當我們一個 if 語句中需要對一個變數進行多個值的判斷時,我們是這樣寫的:

ES5 寫法:

if (type === 1 || type === 2 || type === 3 || type === 4) {
// 邏輯處理
}

ES6 寫法:

ES6 提供了 includes() 函式,用來表示某個陣列是否包含給定的值。所以我們可以這樣寫:

const conditions = [1,2,3,4]
if (conditions.includes(type)) {
// 邏輯處理
}

這樣是不是簡單了很多。當然在沒有 includes() 之前我們也可以使用 indexOf() 進行判斷,兩者都會遍歷陣列來查詢元素,但還是有一些細微的差別:

  • 語義化:

    indexOf() 返回的是元素第一個出現的索引值,如果我們要判斷元素是否存在,還需要去比較返回值是不是等於 -1 ,這樣不夠語義和直觀;而 includes() 直接返回 true 或 false 表示該元素是否在陣列中。
  • 對  NaN  值的處理:

    NaN

    的判斷不準確。

[NaN].indexOf(NaN) // -1
[NaN].includes(NaN) // true

04

獲取物件的屬性值

在 js 中我們經常會需要獲取物件的某個屬性,但是我們往往首先需要判斷一下屬性的上層物件是否存在。

比如我們要讀取 studentInfo.oldStudent.address.city。

ES5 寫法:

// 錯誤寫法
const city = studentInfo.oldStudent.address.city || '';
// 正確寫法
const city = (studentInfo && studentInfo.oldStudent && studentInfo.oldStudent.address && studentInfo.oldStudent.address.city) || '';

由於 city 屬性巢狀較深,在最外層物件的第四層,所以需要判斷四次,每一層是否有值,這種方法顯而易見的繁瑣,表達還不夠清晰。

ES6提供鏈判斷運算子(?.)可以判斷物件是否存在。

上面程式碼我們使用鏈判斷運算子可以這樣寫:

const city = studentInfo?.oldStudent?.address?.city || '';

使用鏈判斷運算子的方法當運算子左側的物件為 null 或 undefined 時,就不會再往下運算了,直接返回我們設定的預設值 。

05

陣列展開

const arr = ['cat', ['lion', 'tiger']]

ES5 寫法:

function flatten(arr) {
let result = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
result = result.concat(flatten(arr[i]));
} else {
result.push(arr[i]);
}
}
return result;
}

這種方法確實可以,那麼我們可以想想更簡單的方法,或許我們是不是還記得陣列的 reduce() 方法的使用呢。

reduce() 方法接收一個函式作為累加器,陣列中的每個值(從左到右)開始縮減,最終計算為一個值。

那麼我們使用 reduce() 方法展開陣列。

const flat = arr => arr.reduce((pre,cur) =>(Array.isArray(cur) ? [...pre,...flat(cur)] : [...pre,cur]), [])
flat(['cat', ['lion', 'tiger']]); // ['cat', 'lion', 'tiger']

其實 ES6 還為我們提供了 flat() 方法,目的就是用來將巢狀的陣列“拉平”,這個方法會返回一個新陣列,對原陣列沒有影響。

['cat', ['lion', 'tiger']].flat()      // ['cat', 'lion', 'tiger']

但是,需要注意的是:

flat() 預設只會展開一層,如果想要展開多層的巢狀陣列,需要為 flat() 提供一個引數用來表示想要展開的層數,預設為 1 。

['cat', ['lion', 'tiger',['dog']]].flat() // ['cat', 'lion', 'tiger', ['dog']]
['cat', ['lion', 'tiger',['dog']]].flat(2) // ['cat', 'lion', 'tiger', 'dog']

如果我們不知道陣列有幾層或不管有多少層巢狀,都要轉成一維陣列,可以用 Infinity 關鍵字作為引數。

['cat', ['lion', 'tiger',['dog']]].flat(Infinity) // ['cat', 'lion', 'tiger', 'dog']

05

結尾

以上只是列舉了我在專案中遇到的幾個場景,對於程式碼的優化需要我們在一點一滴的細節中開始。我們真的應該花點時間靜下心來多思考,程式碼才能越寫越好,一個優美的程式碼不單單減少我們的開發量、提高開發效率,更能以清晰明瞭的方式展示給其他閱讀者,增強可讀性。

最後,以一個小優化題目結束。

ignoreProductFilter() {      
const list = []
products.forEach((item) => {
if (!ignoreList.includes(item.skuId)) {
list.push(item)
}
})
return list
}

動動你的小腦袋優化一下吧(函式內的程式碼用一行搞定)。

掃描下方二維碼新增 「好未來技術」 微信官方賬號

進入好未來技術官方交流群與作者實時互動~

(若掃碼無效,可通過微訊號 TAL-111111 直接新增)

- 也許你還想看 -

從輸入網址到內容返回解析|前端工程師需要掌握這些知識

提高服務穩定性之熔斷怎麼做|文末新春福利

Web前端效能優化深度解讀,這些細節千萬不能忽視

我知道你“在看”喲~