Jinuss's blog Jinuss's blog
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

Web、WebGIS技术博客
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • React

  • Vue

  • JavaScript文章

    • Map和WeakMap
    • Set和WeakSet
    • ES5面向对象
    • ES6面向对象
    • 多种数组去重性能对比
    • 几个高级的JS API
    • JS随机打乱数组
    • 判断是否为移动端浏览器
    • 防抖与节流函数
    • JS获取和修改url参数
    • 比typeof运算符更准确的类型判断
    • Navigator clipboard介绍使用
    • Javascript 语法错题集
    • ESM和CommonJS详解
    • ColorThief的介绍与使用
    • new命令原理
    • 扩展运算符
      • 问题分析
        • 为什么 [...a] 会报错?
        • 为什么 {...a} 能工作?
      • 深入理解
        • 1. 可迭代协议(Iterable Protocol)
        • 2. 对象扩展的工作原理
        • 3. 数组扩展的工作原理
      • 解决方案
        • 1. 使对象可迭代
        • 2. 使用 Object 方法替代
        • 3. 对象扩展的常见用法
      • 关键区别总结
      • 实际应用建议
    • 遍历深层对象指定层级的属性
    • 一文弄懂typeof和instanceof
    • JS中可迭代的数据类型
    • 比较两个字符串的大小
    • requestIdleCallback
  • 学习笔记

  • openlayers

  • threejs

  • MapboxGL

  • 工具

  • 源码合集

  • ECMAScript历年新特性

  • 前端
  • JavaScript文章
东流
2025-08-05
目录

扩展运算符

# 理解对象扩展运算符的行为差异

在 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

# 为什么 [...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. 对象扩展的工作原理

对象扩展运算符会复制源对象的所有可枚举自有属性:

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

# 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

# 解决方案

# 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. 使用 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

# 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

# 关键区别总结

特性 数组扩展 [...obj] 对象扩展 {...obj}
要求 对象必须可迭代 对象必须有可枚举属性
结果 数组 对象
用途 将可迭代对象转为数组 复制/合并对象属性
默认支持 Array, String, Map, Set 等 所有对象
错误情况 对象不可迭代时报错 永远不会报错(对非对象会尝试转为对象)

# 实际应用建议

  1. 对数组使用数组扩展:

    const arr = [1, 2, 3];
    const newArr = [...arr, 4]; // [1, 2, 3, 4]
    
    1
    2
  2. 对对象使用对象扩展:

    const obj = { a: 1, b: 2 };
    const newObj = { ...obj, c: 3 }; // {a:1, b:2, c:3}
    
    1
    2
  3. 需要对象键值对数组时:

    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
new命令原理
遍历深层对象指定层级的属性

← new命令原理 遍历深层对象指定层级的属性→

最近更新
01
requestIdleCallback
08-28
02
比较两个字符串的大小
08-28
03
computed
08-26
更多文章>
Theme by Vdoing | Copyright © 2024-2025 东流 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式