1. Map 比 Object 为什么更好?
-
- Key 类型更灵活
-
- 更直观的内置方法
-
- 处理大型数据性能更好
-
- 保留插入顺序
-
- 避免原型污染
Key 类型更灵活
Object: 对象键 只能是字符串或符号。其他类型(例如对象、函数和数字)会 自动转换为字符串:
const obj = {};
const key = { a: 1 };
obj[key] = '2';
console.log(obj); // { "[object Object]": "2" }
Map: Map 的键可以是 任何类型,包括对象、函数和 NaN:
const map = new Map();
const key = { a: 1 };
map.set(key, '2');
console.log(map.get(key)); // "2"
更直观的内置方法
Object:
obj[key] = value; // 添加属性
obj[key]; // 获取属性的值
delete obj[key]; // 删除属性
Object.keys(obj).length; // 获取属性的数量
Object.keys(obj).forEach(key => { /* ... */ });
Object.values(obj).forEach(value => { /* ... */ });
Object.entries(obj).forEach(([key, value]) => { /* ... */ });
Map:
map.set(key, value); // 添加属性
map.get(key); // 获取属性的值
map.has(key); // 属性是否存在
map.delete(key); // 删除属性
map.clear(); // 删除所有属性
map.size; // 获取属性的数量
map.forEach((value, key) => { /* ... */ });
for (const [key, value] of map) { /* ... */ }
处理大型数据性能更好
- 频繁的增删改查操作:Map 针对频繁的键值插入和删除操作做了优化。
- 处理大型数据集:Map 通常在内存使用和访问速度方面表现更好,尤其是动态生成的键。
保留插入顺序
Map 严格维护键值对的插入顺序,非常适合顺序很重要的场景:
const map = new Map();
map.set('a', 1);
map.set('b', 2);
console.log([...map]); // [['a', 1], ['b', 2]]
避免原型污染
Object容易受到原型链污染:
Copyconst obj = {};
console.log(obj.constructor);
obj.hasOwnProperty('key');
Map 独立于原型链:
const map = new Map();
console.log(map.constructor);
map.set('hasOwnProperty', 'safe');
2. 数据处理的隐藏利器 Set
数组在处理唯一性和查找效率方面存在明显短板,Set
的引入正是为了解决这些问题:
- 重复值问题: 数组允许存储重复值,导致唯一性检查需要额外的逻辑。
- 低效的存在性检查: 查找数组中是否存在某个元素需要线性搜索(如Array.includes),时间复杂度为O(n),对于大型数据集来说性能较差。
常见应用场景
- 去重:快速去除数组中的重复值。
- 存在性检查:高效判断某个值是否存在于集合中。
- 数据集合操作:如并集、交集、差集等。
更直观的内置方法
const mySet = new Set();
// 向Set中添加一个值(如果值已存在,则忽略)
mySet.add(1); // 输出: Set(2) { 1, 2 }
// 从Set中删除指定的值
mySet.delete(1); // 输出: Set(1) { 2 }
// 检查Set中是否存在某个值
console.log(mySet.has(2)); // 输出: true
// 返回Set中元素的数量
console.log(mySet.size); // 输出: 1
// 清空Set中的所有元素
mySet.clear(); console.log(mySet.size); // 输出: 0
// Set是可迭代的,可以通过for...of或forEach进行遍历
const mySet = newSet([1, 2, 3]);
for (const value of mySet) {
console.log(value);
}
// 输出:
// 1
// 2
// 3
mySet.forEach(value =>console.log(value));
// 输出:
// 1
// 2
// 3
Set与数组的性能对比
1. 时间复杂度
- Set在添加、删除和查找操作上的时间复杂度为O(1),
- 而数组的这些操作通常需要O(n)。对于大型数据集,Set的性能优势尤为明显。
2. 适用场景
- 使用Set:当需要快速查找、去重或频繁添加/删除元素时。
- 使用数组:当需要按索引访问元素或维护元素顺序时。
3. 从回调函数到 async/await 的进化
Promise 链式调用(异步优化)
- 扁平链式调用 → 避免嵌套
- 集中错误处理 → .catch()
- 但仍需频繁书写 .then()
async/await(“同步式” 异步)
“async/await 是 Generator 的语法糖,通过状态机和 Promise 实现‘异步转同步’:
- await 暂停函数,返回 Promise → 状态保存
- Promise 完成后恢复执行 → 事件循环调度
- 代码顺序与逻辑顺序一致,但本质仍为异步 → 非阻塞