JAVASCRIPT · ES6+ / 异步编程

JavaScript速查

从类型判断、数组对象高频 API,到异步组合、防抖节流模板与模块运行机制,JS 高频语法与易错点一页随查。

8速查小节 71速查条目 4个组合 API 3阶段事件流

📖 速查表

点击展开各小节

🔤 变量与类型
声明方式要点
let / const 块级作用域 只在块内可见;声明前不可访问,同一作用域禁止重复声明
const 绑定不可变 引用绑定不可重指,对象内容仍可修改;需要完全不可变配合 Object.freeze
暂时性死区 TDZ 声明前访问抛 ReferenceError,连 typeof 也会抛 ⚠ 高频坑
类型判断说明
typeof 适合值类型与函数;typeof null 返回 "object"、数组也返回 "object" 是局限
instanceof 沿原型链判断引用类型;跨 iframe / 跨 realm 场景失效
Object.prototype.toString.call 最通用准确,返回 [object Array] 等内部标签 兜底方案
Array.isArray 判断数组首选,跨环境安全
隐式转换坑说明
== 隐式转换 null == undefined 为 true、类型不同先转换再比;一律 === 免踩坑 ⚠ 规范
NaN NaN !== NaN 恒成立;判断用 Number.isNaN
数组相加 [1,2] + [3]"1,23"——数组先转字符串再拼接;运算前显式转换
拷贝方式实现要点
浅拷贝 Object.assign / 展开运算符,只复制一层,嵌套对象仍是共享引用
JSON 序列化深拷贝 JSON.parse(JSON.stringify(obj)) 简单粗暴;丢 undefined / 函数,循环引用直接报错
structuredClone / 手写递归 现代 API 直接克隆;手写时用 WeakMap 缓存处理循环引用,Date / RegExp / Map / Set 特判 面试高频
📚 数组与对象高频 API
API要点示例
map 映射为新数组,不改变原数组 arr.map(x => x * 2)
filter 过滤返回新数组 arr.filter(x => x > 0)
reduce 聚合为任意结构;务必传初始值,防空数组报错 arr.reduce((s, x) => s + x, 0)
find / findIndex 找第一个匹配项,没有返回 undefined / -1 arr.find(x => x.id === 1)
some / every 至少一个满足 / 全部满足,短路求值返回布尔 arr.some(x => x.done)
flat / flatMap 扁平化默认一层;flatMap 等价 map + flat(1) arr.flat(Infinity) 全展开
at 支持负索引取值 arr.at(-1) 取最后一个
惯用法要点
数组去重 [...new Set(arr)] 一行搞定;对象数组按 key 去重用 Map 缓存
数组分组 reduce 累加器按键归类;新 API Object.groupBy 注意兼容性
sort 排序陷阱 默认按字符串比较,数字要传比较器 (a, b) => a - b ⚠ 高频坑
解构与展开示例
解构默认值 const { name = 'anon', age = 0 } = obj
重命名与嵌套 const { name: userName, addr: { city } } = obj
展开合并 { ...defaults, ...opts } 后者覆盖前者;注意是浅合并
⏳ 异步编程
Promise 基础要点
三态不可逆 pending → fulfilled / rejected,状态一旦改变不再回退
链式调用 then 返回新 Promise,返回值向下穿透;抛错沿链传递直到被 catch 接住
错误处理 链尾 catch 兜底;finally 不接收参数、不改变最终结果
async / await要点
错误处理 await 抛错用 try / catch 捕获,或对单点用 .catch
串行 vs 并行 无依赖的连续 await 是串行浪费;先 Promise.all 打包再 await 性能要点
组合 API行为典型场景
Promise.all 全部成功才成功,一个失败立即 reject 强依赖:所有数据齐了才能渲染
Promise.allSettled 永远 fulfilled,返回 {status, value/reason} 数组 各请求独立处理、互不拖垮
Promise.race 第一个 settle(含失败)决定结果 接口超时控制经典用法 常用
Promise.any 第一个 fulfilled 才返回,全失败抛 AggregateError 多源请求择最快成功者
控制思路要点
并发数控制 维护任务队列 + 活跃计数,完成一个补一个(p-limit 思路),防万请求齐发打爆连接
顺序执行 reduce 串联 Promise 链,或 for await...of 逐个 await
✨ ES6+ 语法糖
语法要点
箭头函数 this 定义时继承外层 this(词法作用域);不能作构造函数、无 arguments ⚠ 高频考点
模板字符串 反引号支持换行与 ${} 插值,替代加号拼接
可选链 ?. obj?.a?.bfn?.():null / undefined 短路不报错
空值合并 ?? 仅 null / undefined 取右侧;与 || 区别:0 和空串不会被吞 ⚠ 易混淆
参数解构默认值 function f({ a = 1 } = {}):不传参也不报错
展开与剩余 fn(...args) 展开;const [first, ...rest] = arr 收集剩余
生成器 function* + yield 惰性产出,可暂停恢复的迭代器,for...of 消费
类字段与私有 #field 真私有字段;static 静态成员,实例不可访问
🌳 DOM 与事件
事件流要点
三阶段 捕获(外 → 内)→ 目标 → 冒泡(内 → 外)
addEventListener 第三参 true 在捕获阶段监听;默认 / false 在冒泡阶段
stopPropagation vs preventDefault 阻断传播与阻止默认行为(如链接跳转)是两件事,别混用
事件委托要点
委托模板 父元素统一监听 + e.target.closest('.item') 找真实目标节点
委托价值 动态新增子元素免重复绑定;大批量列表只挂一个监听器省内存 必会
防抖与节流机制适用
防抖 debounce 停止触发 delay 毫秒后只执行一次,重置计时器 搜索输入联想、窗口 resize 完成后计算
节流 throttle 固定时间间隔内最多执行一次,锁存时间戳 / 定时器 scroll / mousemove / 按钮防连点
常用 API一句话
closest / matches 向上找最近匹配祖先元素 / 当前元素是否匹配选择器
IntersectionObserver 异步监听元素进入视口,懒加载与曝光埋点首选 常用
MutationObserver 监听 DOM 结构与属性变更,调试与第三方脚本场景
requestAnimationFrame 下一渲染帧回调,动画比 setTimeout 更平滑且后台自动暂停
📦 模块化与运行
维度ESMCJS
语法 import / export require / module.exports
加载时机 编译期静态分析,可 tree-shaking 运行时动态加载
导出语义 只读动态绑定(引用,随原模块变化) 值拷贝(导出后与原值脱钩)
顶层特性 this 为 undefined;支持顶层 await this 为 module.exports;模块同步加载
事件循环要点
宏任务 setTimeout / setInterval、I/O、UI 渲染;每轮循环只取一个
微任务 Promise.then / queueMicrotask / MutationObserver;当前宏任务结束后清空整个微任务队列 ⚠ 面试必考
顺序规则 同步代码 → 清空微任务 → 一个宏任务 → 再清微任务,循环往复
事件循环
事件循环:同步跑完清空微任务,再取一个宏任务,渲染按帧率插入,周而复始
strict mode要点
开启方式 文件 / 函数首行 'use strict';ESM 与 class 内默认严格模式
行为变化 未声明变量赋值报错、普通调用 this 不再指向全局、禁 with 与八进制字面量
🧠 this 指向五规则
规则要点示例
默认绑定 独立函数调用:非严格模式指向 window,严格模式与 ESM 下为 undefined fn()
隐式绑定 谁调用指谁;赋值转存会丢失(const f = obj.fn 后调用回退默认绑定) obj.fn()
显式绑定 call / apply 立即调用并指定 this,bind 返回绑定了 this 的新函数 fn.call(ctx)
new 绑定 构造调用绑定到新实例;优先级 new > 显式 > 隐式 > 默认 new Fn()
⚠ 箭头函数 定义时继承外层 this(词法作用域),call / apply / bind 均改不了 () => this
🧬 手写深拷贝要点

简版递归思路:原始值直接返回 → Date 等特殊对象先特判 → WeakMap 缓存斩断循环引用 → 区分数组与对象后逐键递归。

function deepClone(obj, map = new WeakMap()) { if (obj === null || typeof obj !== 'object') return obj; // 原始值直接返回 if (obj instanceof Date) return new Date(obj); // Date 等特殊对象先特判 if (obj instanceof RegExp) return new RegExp(obj); // RegExp 保留 source 与 flags if (map.has(obj)) return map.get(obj); // 循环引用:命中缓存立即返回 const clone = Array.isArray(obj) ? [] : {}; // 区分数组与普通对象 map.set(obj, clone); // 记录已拷贝引用 for (const key of Reflect.ownKeys(obj)) { clone[key] = deepClone(obj[key], map); // 递归拷贝每个属性 } return clone; } // 生产环境优先 structuredClone(obj):原生支持 Map / Set / 循环引用,性能也更好