Appearance
JavaScript 核心
JS 核心题考的是:闭包、原型链、this、事件循环、异步编程。答得出原理才算真正理解 JS。
Q1: 什么是闭包?有什么应用和陷阱? 「🟡 中级」
考察点:JS 作用域链的理解深度。
参考答案:
- 闭包:函数可以访问其词法作用域中的变量,即使函数在作用域外执行。本质是函数 + 它引用的外部变量的环境。
- 应用:数据私有化(模块模式)、函数工厂、柯里化、回调中保持状态。
- 陷阱:循环中的闭包(
var在 for 循环里共享同一个变量,用let或 IIFE 解决);内存泄漏(闭包持有大对象引用无法被 GC)。
javascript
// 经典陷阱
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 输出 3 3 3
}
// 解决:用 let 或 IIFE
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 输出 0 1 2
}追问延伸:
- 闭包在 V8 里是怎么实现的?
- 怎么排查闭包导致的内存泄漏?
Q2: 原型链是什么? 「🟡 中级」
考察点:JS 面向对象的核心机制。
参考答案:
- 每个对象都有
[[Prototype]](__proto__),指向另一个对象;访问属性时沿原型链向上查找,直到 null。 - 构造函数有
prototype属性,new出来的实例的__proto__指向构造函数的prototype。 Object.prototype.__proto__是 null,是原型链的终点。instanceof就是检查原型链上是否存在某个构造函数的 prototype。
追问延伸:
Object.create(null)和{}有什么区别?- ES6 class 和原型继承的关系?
Q3: this 的指向规则? 「🟡 中级」
考察点:this 绑定机制,高频易错题。
参考答案:
- 默认绑定:独立调用指向 window(严格模式 undefined)。
- 隐式绑定:对象方法调用时指向该对象(
obj.fn())。 - 显式绑定:
call/apply/bind强制指定 this。 - new 绑定:构造函数中的 this 指向新创建的实例。
- 箭头函数:没有自己的 this,继承外层作用域的 this。
- 优先级:new > 显式 > 隐式 > 默认。
追问延伸:
setTimeout里的 this 指向谁?- 事件回调里的 this 指向谁?
Q4: 事件循环(Event Loop)是什么? 「🟡 中级」
考察点:JS 异步机制的核心,必问题。
参考答案:
- JS 是单线程的,通过事件循环处理异步任务。
- 执行顺序:同步代码 → 清空微任务队列(Promise.then、MutationObserver)→ 取一个宏任务执行(setTimeout、setInterval、I/O)→ 再清空微任务 → 循环。
- 微任务优先级高于宏任务:Promise 回调会在当前宏任务结束后立即执行,不等下一个宏任务。
javascript
console.log(1);
setTimeout(() => console.log(2), 0);
Promise.resolve().then(() => console.log(3));
console.log(4);
// 输出:1 4 3 2追问延伸:
requestAnimationFrame是宏任务还是微任务?- Node.js 的事件循环和浏览器有什么不同?
Q5: Promise 的状态和链式调用? 「🟢 校招/初级」
考察点:异步编程基础。
参考答案:
- 三种状态:pending → fulfilled / rejected,状态一旦改变不可逆。
.then()返回新的 Promise,实现链式调用;回调的返回值会被Promise.resolve()包装。.catch()捕获前面链路上的错误;.finally()无论成功失败都执行。- 常用组合:
Promise.all()(全部成功)、Promise.race()(最快一个)、Promise.allSettled()(全部完成不管成败)。
追问延伸:
Promise.all里某个 Promise 失败了怎么拿到其他成功的结果?(allSettled)- 怎么手写一个 Promise?
Q6: async/await 的错误处理? 「🟡 中级」
考察点:现代异步编程的规范。
参考答案:
async函数返回 Promise;await暂停执行等待 Promise 完成。- 错误处理:
try/catch包裹 await(推荐)。.catch()链式调用。- 封装工具函数返回
[error, data]元组(Go 风格)。
- 并发:多个独立的 await 用
Promise.all()并行执行,避免串行等待。
追问延伸:
await在循环里串行执行怎么改成并行?- async 函数里的 return 和 throw 分别对应什么?
Q7: 深拷贝怎么实现? 「🟢 校招/初级」
考察点:对象引用与递归。
参考答案:
JSON.parse(JSON.stringify(obj)):简单但有缺陷(不支持函数、undefined、循环引用、Date/RegExp 等)。- 手写递归:处理基本类型、Date、RegExp、Array、Object;用 WeakMap 解决循环引用。
- 现代方案:
structuredClone(obj)(浏览器/Node 原生支持,能处理循环引用)。
追问延伸:
structuredClone有什么限制?(不能拷贝函数、DOM 节点)- 浅拷贝有哪些实现方式?(Object.assign、展开运算符)