ES6 展開運算子

拆拆拆!

喜歡拆禮物嗎?

展開運算子(Spread-Operator),把東西給展開,可以想像是拆禮物的那種感覺 \(•ㅂ•)/

原本你在一個 array 裡面放另外一個 array 會變成二維 array:

1
2
3
const arr = [1, 2, 3]
const arr2 = [4, 5, 6, arr]
console.log(arr2) // [4, 5, 6, [1, 2, 3]]

但「展開運算子」會直接把內容給展開(打開):

1
2
3
const arr = [1, 2, 3]
const arr2 = [4, 5, 6, ...arr]
console.log(arr2) // [4, 5, 6, 1, 2, 3]

可以想像成是把 [1, 2, 3] 的方括號拿掉的感覺。

搭配 function 還有一個很特別的玩法:

1
2
3
4
5
function add(a, b, c) {
return a + b + c
}
let arr = [1, 2, 3]
add(...arr) // 6

不好懂的話,想成這樣就好理解多了:

1
2
3
4
5
function add(a, b, c) {
return a + b + c
}
let arr = [1, 2, 3]
add(1, 2, 3) // 6

object 也可以展開:

1
2
3
4
5
6
7
8
9
let obj = {
a: 1,
b: 2
}
let obj2 = {
c: 1,
...obj
}
console.log(obj2) // {c:1, a: 1, b: 2}

但要注意一下順序的問題,如果有重複的內容,後面的會蓋掉前面的:

1
2
3
4
5
6
7
8
9
10
11
12
let obj = {
a: 1,
b: 2,
c: 10
}
let obj2 = {
c: 1,
...obj
}
// c 會被 obj 給覆寫
// {c: 10, a: 1, b: 2, }
console.log(obj2)

利用展開運算子拷貝 array 或 object

以往我們用 arr1 = arr2 的方式會因為變數的儲存機制導致我們存到的是「記憶體位址」而不是實際上的值。

但改用展開運算子就可以做到複製的動作:

array:

1
2
3
4
const arr1 = [1, 2, 3]
const arr2 = [...arr1]
console.log(arr2) // [1, 2, 3]
console.log(arr1 === arr2) // false

object:

1
2
3
4
const obj1 = {name: 'PeaNu'}
const obj2 = {...obj1}
console.log(obj2) // {name: 'PeaNu'}
console.log(obj1 === obj2) // false

但是,如果是要複製的 array 跟 object是「巢狀結構」的話要特別注意:

1
2
3
4
5
const nestedArray = [4]
const arr1 = [1, 2, 3, nestedArray]
const arr2 = [...arr1]
console.log(arr2) // [1, 2, 3, 4]
console.log(arr2[3] === arr1[3]) // true

你可以把展開運算子想成是「它只能打開第一層」的這種概念,當我們用 arr2 = [...arr1] 的時候,arr1 的第一層會被拆開,變成 1, 2, 3

1
2
3
const arr2 = [...arr1]
const arr2 = [[1, 2, 3]] // 拆掉!
const arr2 = [1, 2, 3]

但是 nestedArray 因為是第二層,所以不會被拆開:

1
2
3
const arr2 = [...arr1]
const arr2 = [[1, 2, 3, [4]]] // 第二層拆不掉!
const arr2 = [1, 2, 3, [4]]

所以 arr1arr2 裡面的 nestedArray 都沒有被拆開,等於裡面放的都是「同一個 nestedArray」,所以 arr2[3] === arr1[3] 才會等於 true。

object 也會有一樣的行為,簡單做個示範:

1
2
3
4
5
6
7
8
const nestedObj = { age: 20 }
const obj1 = {
name: 'PeaNu',
detail: nestedObj
}
const obj2 = {...obj1}
console.log(obj1 === obj2) // false
console.log(obj1.detail === obj2.detail) // true

一樣想成這樣子就好:

1
2
3
4
5
6
7
8
9
10
11
12
const nestedObj = { age: 20 }
const obj1 = {
name: 'PeaNu',
detail: nestedObj
}
// 把 obj1 拆開後
// nestedObj 還是外面那個 nestedObj
const obj2 = {
name: 'PeaNu',
detail: nestedObj
}
console.log(obj1.detail === obj2.detail) // true

背後的原理

以物件來說的話,其實是用 Object.assign 來實現的:

1
2
3
4
const obj = { a: 1 };
// 複製 obj 的內容到 {} 裡面
const copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }

換成 ES6 寫法就是:

1
2
3
4
const obj = { a: 1 };
// 複製 obj 的內容到 {} 裡面
const copy = {...obj};
console.log(copy); // { a: 1 }
mentor-program-day14 ES6 的解構賦值
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×