亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

ES6+ 展開語法

1. 前言

ES6 新增了 ... 的語法糖,主要用于展開語法和剩余語法中,本節先來說說展開語法。展開語法顧名思義可以理解為把整體展開成個體,在 ES5 中如果想把一個數組的內容拷貝到另一個數組中,可以使用 for 循環數組的每一項,然后添加到目標數組中去。但是如果使用展開語法就很方便地完成這個操作了。下面我們就來看看展開語法是如何使用的。

2. 從拷貝說起

2.1 數組拷貝

在 ES5 經常會遇到數組和對象的淺拷貝,我們都知道數組和對象都是引用類型,所以不能像字符串那樣直接賦值,在 ES5 中數組和對象的拷貝都是通過循環來實現的,下面我們來看幾個例子:

var arr1 = [1, 2, 3];
var arr2 = [];
arr1.forEach(function(value){
  arr2.push(value);
}) 
console.log(arr2);	// [1, 2, 3]

上面的代碼是把 arr1 數組中的項拷貝到 arr2 中去,還可以使用數組提供的 concat 和 slice 方法來實現。

var arr1 = [1, 2, 3];
var arr2 = [].concat(arr1);
var arr3 = arr1.slice(0);
arr1.push(4)
console.log(arr1); //[1, 2, 3, 4]
console.log(arr2); //[1, 2, 3]
console.log(arr3); //[1, 2, 3]

在拷貝完后,對 arr1 數組添加元素,可以看到 arr2 和 arr3 沒有發生變化,說明它們不是一個引用地址。這是 ES5 所提供的拷貝方式,那么 ES6 是如何簡化的呢?

var arr1 = [1, 2, 3]; 
var arr2 = [...arr1];
arr1.push(4)
console.log(arr1);	//[1, 2, 3, 4]
console.log(arr2);	//[1, 2, 3]

使用 ... 展開語法可以實現與上面 ES5 實現的相同效果,而且比較簡潔地表達了把 arr1 中的每一項展開放入 arr2 中。

2.2 字面量對象拷貝

上面說到了 ES5 和 ES6 數組拷貝的一個對比,那么針對字面量對象的拷貝二者又是怎么來實現的呢?

ES5 中針對字面量對象的拷貝方式比較少,沒有數組提供的類似的方法可以使用,只能使用循環,但是還可以使用 JSON.stringifyJSON.parse 來實現,但是這個方法存在一些缺陷。 下面看 ES5 中字面量的拷貝實例:

let obj = {a: 1, b: 2};
let copy1 = {};
for(let key in obj) {
  copy1[key] = obj[key] 
}
let copy2 = JSON.parse(JSON.stringify(obj))

上面的兩種方法給出了 ES5 拷貝字面量對象的方法,比較麻煩,也容易出錯。ES6 給出了它的答案:

let obj = {a: 1, b: 2};
let copy = {...obj};

使用展開語法對 obj 進行展開,完美地實現了拷貝過程。

Tips: 這里有必要說明一下,以上的方法都是淺拷貝(只拷貝數組和對象的第一層結構)的過程,對于數組和對象第一層以后的內容,如果是引用類型的存儲方式,則不會進行拷貝操作,也就是不會進行深拷貝。

3. 語法詳情

上面通過拷貝初步了解了展開語法,這里我們給出展開語法的定義:展開語法在函數調用和構造數組時,將字符串和數組在語法層面展開;如果是對象時,將對象的表達式按照 key-value 的方式展開。展開語法的使用主要有以下幾種:

  • 處理字符串、數組和字面量對象;
  • 簡化函數調用時傳參問題;
  • 代替 apply 方法。

3.1 在字符串中的使用

展開語法在處理字符串時,顧名思義可以把字符進行展開,從而得到一個每項都是單個字符串的數組,注意展開語法在字符串使用時,需要包裹在 [] 中才能生效。

const arr = [...'imooc'];
console.log(arr); // ["i", "m", "o", "o", "c"]

在 ES5 中也有方法,可以使用 split 方法實現把字符串變成數組。

const arr = 'imooc'.split('');
console.log(arr); // ["i", "m", "o", "o", "c"]

3.2 在數組中的使用

上面我們講了 ES5 中對一個數組的拷貝,在數組的操作中還有添加、合并等操作的時候,需要調用數組的 slice ()、concat ()、unshift () 等方法,或者組合使用這些方法。

const arr1 = [1, 2];
const arr2 = ['a', ...arr1];
const arr3 = [...arr1, ...arr2];

console.log(arr2);	// ['a', 1, 2]
console.log(arr3);	// [1, 2, 'a', 1, 2]

上面的代碼可以看出,展開語法有很多種不同的使用方式,我們可以把展開語法當成一個整體,直接放到想放到的位置上即可,擴展了操作數組的方式。

3.3 在字面量對象中的使用

和數組一樣,展開語法在字面量對象中的使用方式也有很多種:

const obj1 = {a: 1, b: 2};
const obj2 = {...obj1, c: 30};
console.log(obj2);         // {a:1, b:2, c:30}
const obj3 = {b: 20, c: 30};
const obj4 = {...obj2, ...obj3};  // 合并對象

console.log(obj4);         // {a:1, b:20, c:30}

上面的代碼可以看出,使用方式和數組基本一致,都是把數組或對象中的每一項展開到另一個數組或對象中去。

3.4 函數調用時傳參問題

在函數調用時經常會向函數中傳遞參數,但是,當我們的參數是數組中的項時,我們需要把數組中的每一項取出來,然后傳入函數中,這樣顯得很麻煩,能不能有個方式直接把數組傳入進去呢?首先我們看個求和的例子:

function sum(x, y) {
  return x + y;
}
console.log(sum(1, 2)); // 3

const data = [1,2];
console.log(sum(data[0], data[1]));  // 3

上面的 sum 是一個求和函數,接受兩個參數,我們可以在調用時直接傳遞 2 個參數。但這個時候我們希望求 data 數組中的和,這個時候只能取出 data 中的每一項值傳遞到函數中去,這樣無疑是一個很笨的方法,在 ES5 的時候可以使用 apply() 對函數進行間接的調用解決這個問題。

function sum(x, y, z) {
  return x + y + z;
}
const data = [1,2,3];
console.log(sum.apply(null, data)); // 6

使用 apply() 的方法是解決了這個問題,但是可能會使我們理解代碼增加了難度。有了 ES6 的展開語法,這個問題就會輕而易舉地解決了。

function sum(x, y, z) {
  return x + y + z;
}
const data = [1,2,3];
console.log(sum(...data)); // 6

上面的方法使用展開語法把 data 數組中的每一項進行展開,成為 sum 函數中的三個參數。

4. 小結

本節通過數組和字面量的拷貝引入了 ES6 的展開語法的優勢,又說到了在函數傳參時的應用,可以總結以下幾點:

  1. 可以把 ... 加數組或字面量當作數組或字面量中的一項,任意放入數組或字面量中不同的位置;
  2. 可以通過展開語法對數組和字面量進行淺拷貝;
  3. 在函數傳參數直接把數組中的項進行展開就可以達到傳遞多個參數的目的。