前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库Map Set 链式调用方法
JavaScript数组与集合

Map.set 和 Set.add 为什么能链式调用,delete、clear 可以吗?

能不能链式调用,只看上一个方法返回了什么。map.set() 和 set.add() 返回集合本身,所以能一直点下去;delete() 返回 true 或 false,而 clear() 返回 undefined,接在它们后面再调用就会报错。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#数组与集合#构建工具
先看核心答案读代码示例
理解线索

看返回值决定下一步

  1. set() 和 add()返回当前集合,方便继续添加
  2. delete()返回 true 或 false,告诉你键原本是否存在
  3. clear()返回 undefined,只负责清空

链式调用不是事务。中间某一步抛错时,前面已经执行的 set 不会撤销,集合会停在改了一半的状态。

核心回答

先记住这个答案

map.set(key, value) 和 set.add(value) 执行完后返回的是集合本身,所以可以写成 map.set('a', 1).set('b', 2),每一次调用都作用在同一个集合上。delete 返回布尔值,表示这个键原本存不存在、这次有没有真的删掉;clear 返回 undefined。它们都不返回集合,所以接在后面继续 .set() 会报 TypeError。另外,链式调用是原地修改,不会生成新集合,所有引用这个集合的地方都能看到变化。

  • set 和 add 返回集合本身,可以连着写
  • delete 返回布尔值,表示这次有没有真的删掉
  • clear 返回 undefined,不能再往后链
  • 链式调用修改的是原集合,不会生成新集合

各个方法到底返回什么

把每个方法的返回值直接打印出来,比背结论更直观。

返回值对照JavaScript
const map = new Map()
console.log(map.set('a', 1).set('b', 2) === map)   // set 返回 Map 本身

const set = new Set()
console.log(set.add('a').add('b') === set)         // add 返回 Set 本身

console.log(map.delete('a'), map.delete('a'))      // 第一次删成功,第二次没有可删的
console.log(map.clear() === undefined, map.size)   // clear 没有返回值
console.log(set.size)
查看输出与解释
true
true
true false
true 0
2

前两行的 true 说明链式调用的结果和原集合是同一个对象,没有产生新集合。第三行对同一个键删两次,第一次返回 true,第二次这个键已经不在了,返回 false。所以 delete 的返回值是有用的信息,比如可以用它判断「这个任务是不是真的被取消了」。 如果写成 map.clear().set('c', 3),由于 clear() 返回 undefined,就等于在 undefined 上调用 set,会报错。

链式调用改的是原集合

set 返回的是原集合,所以 const next = map.set('x', 1) 之后,next 和 map 是同一个对象。这一点在 React 里特别容易出问题。

React 里更新 Map 状态
用 useState 存一个 Map,写成 setCache(cache.set(key, value)),传进去的还是原来那个引用。React 用 Object.is 比较新旧状态,发现是同一个对象,就不会重新渲染。正确写法是先复制再改:setCache(prev => new Map(prev).set(key, value))。这里链式调用正好派上用场,new Map(prev) 创建副本,.set() 返回副本本身,一行就能写完。 注意 new Map(prev) 只复制了条目,值如果是对象,新旧 Map 里还是同一个对象。
回答前,多想一步

容易答错的地方

以为链式调用每一步都返回新集合
链式调用的写法和数组的 map、filter 很像,容易让人以为每一步都生成了新集合。其实全程只有一个集合在被修改,赋给新变量也只是多了一个引用。
把 delete 写进链中间
map.delete('a').set('b', 2) 会报错,因为 delete 返回的是布尔值。删除要单独写一行,需要的话检查它的返回值。
试着用自己的话回答

面试官还会怎么问?

Set.add 一个已有的值,size 会变吗?

不会。值已经存在时 add 什么都不改,但仍然返回这个 Set,所以链式调用不会断。也正因为返回值一样,不能靠返回值判断这次有没有真的新增,要在 add 之前用 has 判断。

自己写的类怎么支持链式调用?

在方法最后 return this 就行。比如一个查询构造器,where() 和 orderBy() 都返回 this,就能写成 query.where(...).orderBy(...)。但真正用来返回结果的方法,比如 run(),应该返回结果而不是 this。

链式调用中途报错,前面的修改还在吗?

在。比如 map.set('a', 1).set('b', compute()),当 compute() 抛错时,'a' 已经写进去了。需要要么全部成功要么全部不生效,就先在一个新 Map 里构建好,全部成功后再替换原来的引用。

从一道题,走向一组知识

把知识连起来

数组与集合

Map 的遍历顺序是怎么定的,和对象的属性顺序有什么区别?

链式 set 一个已有的键只会更新值,不会改变它在遍历中的位置,那篇讲清了这个顺序规则。

数组与集合

Map.size 和 Object.keys(obj).length 数的到底是什么?

set 已有键不增加 size,只有 delete 成功才减少,可以用 size 验证每一步的效果。

参考资料

  • MDN:Map.set
  • MDN:Set.add
  • MDN:Map.delete

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 各个方法到底返回什么
  3. 链式调用改的是原集合
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑