了解 TypeScript 中各种数据类型的操作方法是会修改原对象(突变)还是返回新对象,对于写出可预测、无副作用的代码至关重要。下面这个表格总结了字符串、数组和 Map 的常见方法及其返回特性,可以帮助你快速查阅。
数据类型 | 方法 | 是否修改原对象 | 返回值 |
---|---|---|---|
String | 所有方法 (如 slice() , replace() , toUpperCase() , trim() ) |
不修改 | 新的字符串 |
Array | push() , pop() , shift() , unshift() , splice() , sort() , reverse() |
修改 | 通常是操作的元素或数组本身 |
slice() , concat() , map() , filter() , find() , reduce() , flat() |
不修改 | 新的数组或元素 | |
Map | set(key, value) , delete(key) , clear() |
修改 | set() 返回 Map 本身(可链式调用),其余返回布尔值或 undefined |
get(key) , has(key) , keys() , values() , entries() |
不修改 | 相应的值或迭代器 |
💡 核心原则与最佳实践
理解这些行为差异背后的核心原则,能让你更好地掌握 TypeScript。
可变性 vs 不可变性
-
字符串是不可变的:任何对字符串的"修改"操作,本质上都是创建并返回一个全新的字符串。这是所有基本数据类型(如 number, boolean)的共同特性
-
数组和 Map 是可变的:它们是对象(引用类型),其内容可以被直接修改。因此,它们的方法根据设计目的不同,分为修改原对象和不修改原对象两类。
函数式编程与副作用
-
倾向于不修改原数据的方法(如
map
,filter
,slice
)更符合函数式编程范式,有助于减少副作用,使代码逻辑更清晰、更易于调试和测试 -
在 React 等前端框架中,状态不可变是一个核心原则。更新状态时,你必须创建一个新的数组或对象,而不是直接修改原有的状态。
实践建议
- 谨慎使用突变方法:特别是当多个部分代码共享同一个数组或 Map 引用时,意外的修改可能导致难以追踪的 Bug。
利用解构和扩展运算符:它们是不修改原数组的前提下进行操作的利器
// 向数组添加新元素(不修改原数组) const newArr = [...oldArr, newItem]; // 从数组中删除元素(不修改原数组) const newArr = oldArr.filter(item => item.id !== idToRemove);
-
- 明确意图 :选择
slice
(不修改)还是splice
(修改),取决于你的目的是"获取一部分"还是"删除一部分"。清晰的意图能让代码更易读。
- 明确意图 :选择
💎 总结
简单来说,记住这三条规律:
-
字符串 :所有方法都安全无副作用,返回新字符串。
-
数组 :方法名听起来像"动作"的(如
push
,sort
)通常会修改 原数组;方法名听起来像"查询"或"创建"的(如map
,slice
)通常返回新数组。
Map :set
、delete
、clear
会修改原 Map,其他查询方法则不会。