展开操作符(...)会把数组或对象的元素“拷贝一份”放进新的数组或对象里,
原来的数组 / 对象本身不会被修改。
但拷贝是“浅拷贝”,不是深拷贝。
二、这段代码做了什么
1 2 3 4
| let first = [1, 2] let second = [3, 4]
let bothPlus = [0, ...first, ...second, 5]
|
等价理解为:
1
| let bothPlus = [0, 1, 2, 3, 4, 5]
|
关键点
bothPlus 是 一个全新的数组
first 和 second 没有被修改
三、浅拷贝
1️⃣ 对基本类型(number / string)
1 2 3 4 5 6
| let a = [1, 2] let b = [...a]
b[0] = 100
a
|
因为:
2️⃣ 对引用类型(对象 / 数组)
1 2 3 4 5 6
| let a = [{ x: 1 }] let b = [...a]
b[0].x = 999
a
|
原因:
这就是 浅拷贝 的准确含义。
四、“与解构相反”
| 操作 |
做的事 |
| 解构 |
从数组 / 对象里 取值出来 |
| 展开 |
把数组 / 对象里的值 铺开塞进去 |
解构
展开
一个是“拆”,一个是“铺”。
五、对象展开也是同一套规则
1 2 3 4
| const obj1 = { a: 1 } const obj2 = { b: 2 }
const merged = { ...obj1, ...obj2 }
|
merged 是新对象
obj1 / obj2 不变
- 浅拷贝
1 2 3 4 5
| const obj1 = { a: { x: 1 } } const obj2 = { ...obj1 }
obj2.a.x = 2 obj1.a.x
|
展开对象
1 2
| let defaults = { food: "spicy", price: "$$", ambiance: "noisy" }; let search = { ...defaults, food: "rich" };
|
food属性会重写
对象展开还有其它一些限制。
它仅包含对象 自身的可枚举属性。
当展开一个对象实例时,会丢失其方法;
六、总结
展开操作符会创建一个“新的容器”,
但容器里的引用元素仍然指向原来的对象,
所以叫“浅拷贝”,原数组 / 对象本身不会被修改