ES6-展開運算子(Spread Operator)、其餘參數(Rest Operator)

展開運算子(Spread Operator)、其餘參數(Rest Operator)

展開運算子( Spread Operator )

展開運算子是”把一個陣列展開(expand)成個別數值“的速寫語法,簡單來說,就是把陣列裡面的值,拆解成一個一個

基本用法
1
2
3
4
5
6
7
//陣列
let number = [1,2,3,4,5];
console.log(...number); // 1,2,3,4,5

//字串
let str = 'kanboo'
console.log(...str); // "k","a","n","b","o","o"
將二個Array合併(新舊寫法比較)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//===========過去寫法===========
let groupA = ['爸爸', '媽媽'];
let groupB = ['老大','老二','老么'];

const groupAll = groupA.concat(groupB);
console.log(groupAll);
// ["爸爸", "媽媽", "老大", "老二", "老么"];


//===========新的寫法===========
let groupA = ['爸爸', '媽媽'];
let groupB = ['老大','老二','老么'];

const groupAll = [...groupA, ...groupB]; //拆解完後,再用陣列[]包起來,產生新的陣列
console.log(groupAll);
// ["爸爸", "媽媽", "老大", "老二", "老么"];

你也可以用來把陣列展開,傳入函式之中,例如下面加總函式的範例:

將 陣列展開 傳入函式
1
2
3
4
5
6
function sum(a, b, c) {
return a + b + c;
}

var args = [1, 2, 3];
console.log(sum(...args)); // 6

淺層複製

另外陣列物件相同都有著傳參考的特性,所以當把陣列賦予到另一個值上時,修改其中一個另一個也會跟著變動。

傳址:更動groupB 會 影響groupA
1
2
3
4
5
6
7
8
9
// 由於傳參考的關係,所以將一個陣列傳到另一個上時
// 兩個的值其實是一樣的
let groupA = ['老大','老二','老么'];
let groupB = groupA;
groupB.push('小花');

//輸出
console.log(groupA); // ['老大','老二','老么','小花'];
console.log(groupB); // ['老大','老二','老么','小花'];

由於 展開運算子 它是一個一個將值寫入,所以他也有淺層的複製(shallow copy) 。

淺層複製:更動groupB 不會 影響groupA
1
2
3
4
5
6
7
8
// 這個屬於淺拷貝,所以不會影響到另一個物件
let groupA = ['老大','老二','老么'];
let groupB = [...groupA];
groupB.push('小花');

//輸出
console.log(groupA); // ['老大','老二','老么'];
console.log(groupB); // ['老大','老二','老么','小花'];
注意

因為是淺層的複製,所以當陣列的值是放 物件 的話,依舊會因為傳參考的特性,而修改其中一個另一個也會跟著變動。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let groupA = [{name:'老大'},{name:'老二'},{name:'老三'}];
let groupB = [...groupA];

groupB.push({name:'小花'});

//輸出
console.log(groupA); // [{name:'老大'},{name:'老二'},{name:'老三'}]
console.log(groupB); // [{name:'老大'},{name:'老二'},{name:'老三'},{name:'小花'}]

debugger;

//更改 groupB 第一個Name
groupB[0].name = "爸爸";

//注意 groupA 的第一個Name,也會跟著被變動
console.log(groupA); // [{name:'爸爸'},{name:'老二'},{name:'老三'}]
console.log(groupB); // [{name:'爸爸'},{name:'老二'},{name:'老三'},{name:'小花'}]

類陣列轉成純陣列

JavaScript 中有許多陣列,這類陣列有著陣列的外皮,但卻不能使用陣列的方法,這類陣列由於原型不同,所以 不能 使用許多的陣列方法,如: map(), concat() 等等。

其中一種很常見的就是 DOM 陣列,此時我們就可以用 展開運算子 轉為 純陣列,這樣就可以使用陣列的各種方法。

1
2
3
4
5
// 可以將類陣列轉成陣列
let doms = document.querySelectorAll('p');
console.log(doms);
let spreadDom = [...doms];
console.log(spreadDom);

範例 arguments

以前要使用函式的 arguments 時,寫法僅可用 forfor..in 依序取得參數值。

arguments傳統寫法
1
2
3
4
5
6
7
8
9
function sum() {
var total = 0;
for( var i=0; i<arguments.length; i++ ) {
total += arguments[i];
}
return total;
}

console.log( sum(1, 2, 3, 4, 5) ); // 15

但是若將 arguments 改寫用 陣列的方法(forEach、map、reduce) 的話,程式碼就會出錯

使用陣列方法,會Error
1
2
3
4
5
6
7
8
9
function sum() {
var total = 0;
arguments.forEach(function(element) {
total += element;
});
return total;
}

console.log(sum(1, 2, 3, 4, 5)); //error TypeError: arguments.forEach is not a function

現在可透過 展開運算子 轉為 陣列,就可使用 陣列的方法(forEach、map、reduce)。

透過「展開運算子」轉換
1
2
3
4
5
6
7
8
9
10
function sum() {
let arg = [...arguments]; //透過 展開運算子 來轉成純陣列
let total = 0;
arg.forEach(function(element) {
total += element;
});
return total;
}

console.log(sum(1, 2, 3, 4, 5)); //15

其餘參數(Rest Operator)

有時候,Function 接受的參數數量不固定,而 其餘參數(Rest Operator) 的功能就是把多的參數併成一個 Array

範例1

可傳入不固定的參數,1個 or 多個 皆可..

1
2
3
4
5
6
7
8
9
10
11
12
function sum(...numbers) {
var result = 0;
numbers.forEach(function (number) {
result += number;
});
return result;
}

//傳入一個值
console.log(sum(1)); // 1
//傳入多個值
console.log(sum(1, 2, 3, 4, 5)); // 15

範例2

如果function有先定義別的參數,就會將傳入的參數值先給定義好的參數,剩下的就全部塞入其餘參數

1
2
3
4
5
6
7
8
function restArray(x, y, ...others) {
console.log("x",x); // x: 1
console.log("y",y); // y: 2
console.log("others",others); // others: [3, 4, 5]
}

//拆解陣列
restArray(1, 2, 3, 4, 5);

其餘參數(Rest parameters)有一個限制,就是這個參數一定是函式的「最後一個」。

你如果放在其餘的參數,就會產生錯誤

反過來寫就會Error
1
2
3
4
5
6
7
8
function restArray(...others, x, y) {
console.log("x",x);
console.log("y",y);
console.log("others",others);
}

//拆解陣列
restArray(1, 2, 3, 4, 5); //error SyntaxError: Rest parameter must be last formal parameter
其餘的參數 與 arguments 不同的是:
- arguments 不是真的陣列,其餘參數則「」。
- arguments 不能混用自訂傳入的參數。

參考來源