 扩展运算符
扩展运算符
  # 理解对象扩展运算符的行为差异
在 JavaScript 中,扩展运算符 ... 的行为会根据上下文有所不同。让我们深入分析为什么[...a] 会报错而 {...a} 却能正常工作。
# 问题分析
const a = {s:4, y:7};
// 这行会报错
[...a]; // TypeError: a is not iterable
// 这行能正常工作
let b = {...a}; // b = {s:4, y:7}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 为什么 [...a] 会报错?
 数组扩展运算符 [...value] 要求 value 必须是可迭代对象。普通对象默认不是可迭代的,因此会抛出错误。
# 为什么 {...a} 能工作?
 对象扩展运算符 {...value} 会复制 value 的所有可枚举自有属性到一个新对象中。普通对象有可枚举属性,因此可以正常工作。
# 深入理解
# 1. 可迭代协议(Iterable Protocol)
要使对象可迭代,它必须实现 Symbol.iterator 方法:
const iterableObject = {
  data: [1, 2, 3],
   {
    let index = 0;
    return {
      next: () => {
        if (index < this.data.length) {
          return { value: this.data[index++], done: false };
        }
        return { done: true };
      }
    };
  }
};
console.log([...iterableObject]); // [1, 2, 3]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 2. 对象扩展的工作原理
对象扩展运算符会复制源对象的所有可枚举自有属性:
const obj = { a: 1, b: 2 };
const clone = { ...obj }; // { a: 1, b: 2 }
// 等同于
const manualClone = {};
for (const key in obj) {
  if (Object.prototype.hasOwnProperty.call(obj, key)) {
    manualClone[key] = obj[key];
  }
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 3. 数组扩展的工作原理
数组扩展运算符要求对象实现迭代器协议:
const arrayLike = {
  0: 'a',
  1: 'b',
  length: 2,
   {
    let index = 0;
    return {
      next: () => {
        if (index < this.length) {
          return { value: this[index++], done: false };
        }
        return { done: true };
      }
    };
  }
};
console.log([...arrayLike]); // ['a', 'b']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 解决方案
# 1. 使对象可迭代
如果你想对普通对象使用数组扩展运算符,需要实现 Symbol.iterator 方法:
const a = {
  s: 4,
  y: 7,
   {
    const keys = Object.keys(this);
    let index = 0;
    
    return {
      next: () => {
        if (index < keys.length) {
          const key = keys[index++];
          return { value: [key, this[key]], done: false };
        }
        return { done: true };
      }
    };
  }
};
console.log([...a]); 
// [['s', 4], ['y', 7]]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2. 使用 Object 方法替代
更常见的是使用 Object 方法来处理对象属性:
const a = {s:4, y:7};
// 获取键数组
console.log(Object.keys(a)); // ['s', 'y']
// 获取值数组
console.log(Object.values(a)); // [4, 7]
// 获取键值对数组
console.log(Object.entries(a)); // [['s', 4], ['y', 7]]
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 3. 对象扩展的常见用法
对象扩展运算符在多种场景下非常有用:
// 合并对象
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const merged = { ...obj1, ...obj2 }; // {a:1, b:2}
// 添加新属性
const withNewProp = { ...a, z: 10 }; // {s:4, y:7, z:10}
// 覆盖属性
const overridden = { ...a, s: 100 }; // {s:100, y:7}
// 创建浅拷贝
const shallowCopy = { ...a };
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 关键区别总结
| 特性 | 数组扩展 [...obj] | 对象扩展 {...obj} | 
|---|---|---|
| 要求 | 对象必须可迭代 | 对象必须有可枚举属性 | 
| 结果 | 数组 | 对象 | 
| 用途 | 将可迭代对象转为数组 | 复制/合并对象属性 | 
| 默认支持 | Array, String, Map, Set 等 | 所有对象 | 
| 错误情况 | 对象不可迭代时报错 | 永远不会报错(对非对象会尝试转为对象) | 
# 实际应用建议
- 对数组使用数组扩展: - const arr = [1, 2, 3]; const newArr = [...arr, 4]; // [1, 2, 3, 4]1
 2
- 对对象使用对象扩展: - const obj = { a: 1, b: 2 }; const newObj = { ...obj, c: 3 }; // {a:1, b:2, c:3}1
 2
- 需要对象键值对数组时: - const obj = { a: 1, b: 2 }; const entries = Object.entries(obj); // [['a',1], ['b',2]]1
 2
理解这些区别有助于避免常见的错误,并写出更健壮的 JavaScript 代码。
编辑  (opens new window)
  上次更新: 2025/08/05, 08:02:06
