[JavaScript] Javascript ES6 中的展開/其餘運算子(Spread operator/Rest operator)
展開/其餘運算子(Spread operator/Rest operator) 都是 Javascript ES6 中的特性,兩者的符號雖然都是 …
,但是在使用上略有差異。
Outline:
+ 展開運算子(Spread operator)
+ 其餘運算子(Rest operator)
+ 總結與差異 Summary&Differences
展開運算子(Spread operator)
又稱展開運算符、Spread syntax,會將陣列展開成個別值灑進去。
常見用途 1 — 似 cancat 用法
在 spread operator 出現之前,如果我們要結合兩個陣列,concat 會是一種常見的方式:
var arr1 = ['emma','is'];
var arr2 = [18,'years old'];var combinedArr = arr1.concat(arr2);console.log(combinedArr); // ["emma", "is", 18, "years old"]
透過 spread operator,就可以簡略為:
var arr1 = ['emma','is'];
var arr2 = [...arr1, 18,'years old'];console.log(arr2); // ["emma", "is", 18, "years old"]
或多個 spread operator 放在一起:
var arr1 = ['emma','is'];
var arr2 = [18,'years old'];var combinedArr = [...arr1, ...arr2];console.log(combinedArr); // ["emma", "is", 18, "years old"]
也可以做為陣列的淺拷貝(不會影響到被拷貝的陣列):
var arr1 = ['emma','is'];
var arr2 = [...arr1];arr2.push(18, 'years old'); // 不會影響到 arr1
console.log(arr2); // ["emma", "is", 18, "years old"]
console.log(arr1); // ['emma', 'is']
常見用途 2 — 傳入函式作為參數
在 ES6 之前,如果要將陣列展開傳入函式,會用上 apply
這個方法,他的第二個參數是陣列,apply
的詳細說明可以看 w3c:
function mySum(x,y){
return x+y;
}
var arr = [1,2];
mySum.apply(null, arr) // 3
使用 spread operator 則方便許多:
function mySum(x, y){
return x+y;
}var arr = [1,2];
Sum(...arr); // 3
常見用途 3 — 將可迭代 (literable) 的物件轉為陣列
Javascript 中可迭代的物件有 String, Array, TypedArray, Map, Set 物件:
const name = 'emma';
const spreadName = [...name];console.log(spreadName) // ['e','m','m','a']
其餘運算子(Rest operator)
又稱為其餘運算符,可以將剩下的值集合成一個陣列。
常見用途 1 — 其餘參數 (Rest parameters)
用於想要傳入一個不確定數量的值給函式作為參數:須注意在傳入函式時,必須是參數中的最後一位,而且參數中只能有一個其餘參數
// 回傳參數加總
function sumUp(...nums){
console.log(nums); // 傳入的參數被組成陣列 let total = 0;
nums.forEach((number)=>{
total += number; // 將陣列內的數字加總起來
})
return total; // 回傳 total
}sumUp(1) // [1], 1
sumUp(1,2,3) // [1,2,3], 6
傳入多個參數:
function many(x,y, ...z){ // 指定了兩個參數和一個剩餘參數
console.log('x:',x); // 印出 x
console.log('y:',y); // 印出 y
console.log('z:',z); // 印出剩餘參數 z
}many('emma', 'is', 18, 'years', 'old');
// x: emma
// y: is
// z: [18,'years','old'] // 後面剩下的被組成一個陣列了
即使只有傳入一個值,也會被組成陣列:
many('emma', 'is', 'good')
// x: emma
// y: is
// z: ['good']
如果沒有傳入值,就會成為一個空的陣列,而不是 undefined
:
many('emma', 'is')
// x: emma
// y: is
// z: []
常見用途 2 — 解構賦值 (destructuring)
解構賦值可以想像成鏡像的方式來進行賦值,
解構陣列:
const [a,b] = [1,2];
console.log(a); // 1
console.log(b); // 2
使用其餘運算子解構陣列:
const [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3]
解構物件:
let me = {
name: 'emma',
age: 18
};let { name, age } = me;
console.log(name); // emma
console.log(age); // 18
使用其餘運算子解構物件 :
let {a, b, ...rest} = { a:1, b:2, c:3, d:4 };
console.log(a); // 1
console.log(b); // 2
console.log(rest); // {c:3, d:4}
如果和其餘參數出現一樣的狀況,數量不相等時,也會成為空的陣列:
let [c, ...d] = [1]
console.log(c); // 1
console.log(d); // []
總結與差異 Summary&Differences
展開運算子的概念可以想成是一種灑進去的感覺,把陣列或是可迭代的物件展開成一個一個獨立的值,再灑進使用他的地方。而其餘運算子則是集合剩下來的值組合成陣列,讓我們可以傳遞未知數量的參數至函式中
📝 Quiz time !
以下取自 JavaScript Questions 中有關 hoisting 的小測驗,希望看完上面的說明,下面的題目可以讓你迎刃而解:
What does this return?
[...'Lydia'];
- A:
["L", "y", "d", "i", "a"]
- B:
["Lydia"]
- C:
[[], "Lydia"]
- D:
[["L", "y", "d", "i", "a"]]
Answer: A
這裡是展開運算子的做法,會將可迭代物件撒開
What’s the output?
const user = { name: 'Lydia', age: 21 };
const admin = { admin: true, ...user };console.log(admin);
- A:
{ admin: true, user: { name: "Lydia", age: 21 } }
- B:
{ admin: true, name: "Lydia", age: 21 }
- C:
{ admin: true, user: ["Lydia", 21] }
- D:
{ admin: true }
Answer: B
這裡也是展開運算子的作法,可以將兩個物件結合, user 物件裡面單個 key/value 被拆開來灑進 admin 物件中。
內容若有任何錯誤,歡迎留言交流指教! 🦕
ref:
JavaScript ES6: Spread Operator and Rest Parameters
展開運算符與其餘運算符
MDN-Spread syntax (…)
MDN-Rest parameters