标签:ES6、JavaScript、性能优化、代码简化
"代码写得少,Bug 自然少。"------鲁迅(并没有说)
今天不聊 React、不聊 Vue,回到语言层,挖一挖那些"官方早就给了,但我们总自己造轮子"的 ES6 冷门 API。
它们每一个都经过浏览器真·原生实现,无 polyfill 也能跑 ,一句顶五句,看完直接复制粘贴就能让同事惊呼"还有这种操作?"。
1. 数组拍平:flat / flatMap
场景:后端把树形结构一股脑塞给你,前端只想拿叶子节点。
js
// 商品按类目嵌套:[[手机,耳机],[笔记本,鼠标]]
const goods = [['iPhone','AirPods'],['MacBook','MagicMouse']];
// 旧写法
const all = goods.reduce((a, b) => a.concat(b), []);
// 新写法
const all = goods.flat(); // 默认 1 层
const deep = goods.flat(Infinity); // 无限层
bonus :flatMap = map + flat(1)
,一次循环搞定"一对多"映射。
js
const users = [{name:'张三',tags:'前端,TS'},{name:'李四',tags:'后端,Go'}];
const pairs = users.flatMap(u => u.tags.split(',').map(t => ({name:u.name, tag:t})));
// [{name:'张三',tag:'前端'}, {name:'张三',tag:'TS'}, ...]
2. 对象 ↔ 数组"瞬移":entries ↔ fromEntries
场景 :只想给对象做"过滤 / 映射 / 排序",又懒得写 reduce
。
js
const score = { 语文:95, 数学:82, 英语:76 };
// 保留 >80 的学科
const pass = Object.fromEntries(
Object.entries(score).filter(([k,v]) => v > 80)
);
// { 语文:95, 数学:82 }
URL 解析也能一行完成:
js
const params = Object.fromEntries(new URLSearchParams('name=张三&age=25'));
// { name:'张三', age:'25' }
3. 字符串补全:padStart / padEnd
场景:时间、订单、身份证,位数必须对齐。
js
const now = new Date();
const time = `${now.getHours().toString().padStart(2,'0')}:${now.getMinutes().toString().padStart(2,'0')}`;
// "09:05" 而不是 "9:5"
固定编号:
js
const orderId = '457';
const fullId = orderId.padStart(8, '0'); // "00000457"
4. 数组去重 + 集合运算:Set
场景:接口返回了 1w 条数据,里面重复 ID 占 30%。
js
const ids = [3,5,5,7,3,9];
const unique = [...new Set(ids)]; // [3,5,7,9]
// 交集 / 差集,同样一行
const a = new Set([1,2,3]);
const b = new Set([3,4,5]);
const intersect = [...a].filter(v => b.has(v)); // [3]
const diff = [...a].filter(v => !b.has(v)); // [1,2]
5. 解构"嵌套 + 默认值"
场景:接口字段经常缺失,还要做降级。
js
function ajax({
url,
method = 'GET', // 默认值
timeout = 5000,
headers: { token = '' } = {} // 嵌套默认值
} = {}) {
console.log(url, method, token);
}
深层安全取值:
js
const { address: { city, detail = '暂无' } = {} } = user;
// 无论 user.address 是否存在都不会报错
6. 真正"私有"属性:Symbol
场景:写工具库,怕用户覆盖你的内部字段。
js
const _secret = Symbol('secret');
class Cache {
[_secret] = new Map();
set(k,v){ this[_secret].set(k,v); }
get(k){ return this[_secret].get(k); }
}
const c = new Cache();
c['secret'] = 123; // 不影响内部
console.log(c[_secret]); // 外部拿不到
还能改 toString 标签:
js
class Queue {
[Symbol.toStringTag] = 'Queue';
}
`${new Queue}`; // "[object Queue]"
7. 对象操作"统一入口":Reflect
场景:写 Proxy 拦截,总担心"死循环"。
js
const proxy = new Proxy(target, {
get(t, k){
console.log('read', k);
return Reflect.get(t, k); // 调用原始行为,安全
}
});
安全删除:
js
const ok = Reflect.deleteProperty(obj, 'a'); // 返回布尔,可判断
8. 异步"扫尾"神器:finally()
场景:请求结束必须关 loading,成功失败都得关。
js
function load(){
showLoading();
return fetch('/api/data')
.then(render)
.catch(showError)
.finally(hideLoading); // 只写一次
}
结语:如何无痛养成"新习惯"?
- 代码评审刻意问一句 :这里能用
flatMap
/fromEntries
吗? - 立 Flag:连续三周在业务里用满这 8 个 API,每用一次给自己打 ★。
- 团队分享:把本文甩到群里,谁最晚在 PR 里用到,请全组奶茶 🧋。
"轮子"官方已经造好,下次再手写 reduce
去重,就罚自己抄十遍 flat(Infinity)
吧!