想寫出優雅的程式碼?試試這些ES6小tips

saku發表於2018-07-15

最近又重溫了ES6的文件,發現除了箭頭函式,解構賦值,擴充套件運算子這樣常用的語法外,還有很多很給力的方法,不僅使程式碼更簡潔,還可以提高程式碼的健壯性,更令我意外的是,瀏覽器相容大部分的方法,無需babel也可完美執行。所以覺得很有必要整理一下,在專案中,拋棄陳舊的老古董寫法,升級為ES6規範程式碼。

一.陣列升級

1.擴充套件運算子之複製陣列

//es5做法
const a1 = [1, 2]
const a2 = a1.concat()

a2[0] = 2
a1 //[1,2] 修改a2不會對a1有影響
複製程式碼

擴充套件運算子提供了複製陣列的簡便寫法:

//es6做法
const a1 = [1, 2]
const a2 = [...a1]
//or
const [...a2] = a1

a2[0] = 2
a1 //[1,2] 修改a2不會對a1有影響
複製程式碼

注:上述複製的過程是深拷貝,但是要注意的一點是,concat和擴充套件運算子用做合併陣列時,都是淺拷貝。

2.陣列例項的find()和findIndex()

find方法,用於找出第一個符合條件的陣列成員,它的引數是一個回撥函式,所有陣列成員依次執行該回撥函式,直到找出第一個返回值為true的成員,然後返回該成員。如果沒有符合條件的成員,則返回undefined。

//es5做法
const arr = [1,5,10,15]
for(var i=0;i<arr.length;i++) {
    if(arr[i]>5) {
        return arr[i]
    }
} //10
//es6做法
[1,5,10,15].find(function(value,index,arr) {
    return value > 5
}) //10
複製程式碼

另外,這兩個方法都可以發現NaN,彌補了indexOf方法的不足。

[NaN].indexOf[NaN] //-1

[NaN].findIndex(y => Object.is(NaN,y)) //0
複製程式碼

3.陣列例項的includes()

該方法返回一個布林值,表示某個陣列是否包含給定的值。沒有該方法之前,我們通常使用陣列的indexOf方法,檢查是否包含某個值。

indexOf方法有兩個缺點,一是不夠語義化,它的含義是找到引數值的第一個出現位置,所以要去比較是否不等於-1,表達起來不夠直觀。二是,它內部使用嚴格相等運算子(===)進行判斷,這會導致對NaN的誤判。

[NaN].indexOf[NaN] //-1

[NaN].includes(NaN) //0
複製程式碼

注:Map和Set資料結構有一個has方法,注意與includes區分。Map結構的has方法,是來查詢鍵名的 Set結構的has方法,是用來查詢鍵值的。

二.物件升級

1.Object.assign()

用於物件的合併,將原物件的所有可列舉屬性,複製到目標物件上。

object.assign拷貝的屬性是有限制的,只拷貝源物件自身的屬性(不拷貝繼承屬性,也不拷貝不可列舉的屬性)

//為物件新增屬性和方法
//es6
class Point {
 constructor(x, y) {
   Object.assign(this, {x, y});
 }
}
Object.assign(Point.prototype, {
 addPoint(arg1, arg2) {
   ···
 }
});
複製程式碼

這個方法很常用,但一些細節問題還是要拎出來提醒自己注意一下。

(1)淺拷貝

Object.assign方法實行的是淺拷貝,而不是深拷貝。也就是說,如果源物件某個屬性的值是物件,那麼目標物件拷貝得到的是這個物件的引用。

(2)同名屬性的替換

對於這種巢狀的物件,一旦遇到同名的屬性,Object.assign的處理方法是替換,而不是新增。要特別注意!!

(3)陣列的處理

Object.assign可以用來處理陣列,但是會把陣列視為物件。

2.屬性的遍歷

ES6 一共有 5 種方法可以遍歷物件的屬性。

(1)for...in

for...in迴圈遍歷物件自身的和繼承的可列舉屬性(不含 Symbol 屬性)。

(2)Object.keys(obj)

Object.keys返回一個陣列,包括物件自身的(不含繼承的)所有可列舉屬性(不含 Symbol 屬性)的鍵名。

(3)Object.getOwnPropertyNames(obj)

Object.getOwnPropertyNames返回一個陣列,包含物件自身的所有屬性(不含Symbol屬性,但是包括不可列舉屬性)的鍵名。

(4)Object.getOwnPropertySymbols(obj)

Object.getOwnPropertySymbols返回一個陣列,包含物件自身的所有 Symbol 屬性的鍵名。

(5)Reflect.ownKeys(obj)

Reflect.ownKeys返回一個陣列,包含物件自身的所有鍵名,不管鍵名是 Symbol 或字串,也不管是否可列舉。

三. 函式升級

1.rest引數

用於獲取函式的多餘引數,這樣就不需要使用arguments物件了。

// arguments變數的寫法
function sortNumbers() {
  return Array.prototype.slice.call(arguments).sort();
}

// rest引數的寫法
const sortNumbers = (...numbers) => numbers.sort();
複製程式碼

2.箭頭函式

ES6 允許使用“箭頭”(=>)定義函式。

// arguments變數的寫法
function sortNumbers() {
  return Array.prototype.slice.call(arguments).sort();
}

// rest引數的寫法
const sortNumbers = (...numbers) => numbers.sort();
複製程式碼

注意點:

(1)函式體內的this物件,就是定義時所在的物件,而不是使用時所在的物件。

(2)不可以當作建構函式,也就是說,不可以使用new命令,否則會丟擲一個錯誤。

(3)不可以使用arguments物件,該物件在函式體內不存在。如果要用,可以用 rest 引數代替。

四.for...of迴圈

for...of迴圈可以使用的範圍包括陣列、Set 和 Map 結構、某些類似陣列的物件(比如arguments物件、DOM NodeList 物件)、後文的 Generator 物件,以及字串。

1.用法

陣列:

//為物件新增屬性和方法
//es6
const arr = ['red', 'green', 'blue'];

for(let v of arr) {
  console.log(v); // red green blue
}
複製程式碼

Set 和 Map 結構

var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
for (var e of engines) {
 console.log(e);
}
// Gecko
// Trident
// Webkit

var es6 = new Map();
es6.set("edition", 6);
es6.set("committee", "TC39");
es6.set("standard", "ECMA-262");
for (var [name, value] of es6) {
 console.log(name + ": " + value);
}
// edition: 6
// committee: TC39
// standard: ECMA-262
複製程式碼

類陣列的物件

// 字串
let str = "hello";

for (let s of str) {
 console.log(s); // h e l l o
}

// DOM NodeList物件
let paras = document.querySelectorAll("p");

for (let p of paras) {
 p.classList.add("test");
}

// arguments物件
function printArgs() {
 for (let x of arguments) {
   console.log(x);
 }
}
printArgs('a', 'b');
// 'a'
// 'b'
複製程式碼

2.與其他遍歷語法的比較

for...in迴圈有幾個缺點。

  • 陣列的鍵名是數字,但是for...in迴圈是以字串作為鍵名“0”、“1”、“2”等等。
  • for...in迴圈不僅遍歷數字鍵名,還會遍歷手動新增的其他鍵,甚至包括原型鏈上的鍵
  • 某些情況下,for...in迴圈會以任意順序遍歷鍵名。 總之,for...in迴圈主要是為遍歷物件而設計的,不適用於遍歷陣列。

forEach迴圈的缺點是無法中途跳出forEach迴圈,break命令或return命令都不能奏效。

與之相對的,for...of有如下優點:

  • 有著同for...in一樣的簡潔語法,但是沒有for...in那些缺點。
  • 不同於forEach方法,它可以與break、continue和return配合使用。
  • 提供了遍歷所有資料結構的統一操作介面。

五.參考網址

http://es6.ruanyifeng.com/#docs/iterator#for---of-%E5%BE%AA%E7%8E%AF

相關文章