01 - JavaScript深度理解¶
目标: 深入理解JavaScript核心机制,能手写Promise等核心API
时间: 2周
核心原则: 理解原理比会用更重要
🎯 为什么需要深入理解JavaScript?¶
实际场景¶
Text Only
场景1: 异步代码执行顺序混乱
- 不了解事件循环 → 无法预测代码执行顺序
- 不了解微任务宏任务 → 出现诡异bug
场景2: 内存泄漏
- 不了解闭包原理 → 造成内存泄漏
- 不了解垃圾回收 → 无法优化内存使用
场景3: 框架原理理解困难
- 不了解原型链 → 难以理解Vue/React的继承机制
- 不了解ES Module → 难以理解构建工具
📚 核心知识点¶
1. 执行上下文与作用域¶
JavaScript
// 执行上下文类型
// 1. 全局执行上下文
// 2. 函数执行上下文
// 3. Eval执行上下文
// 作用域链:内部函数可沿作用域链向上查找外部变量
function outer() {
const a = 1; // outer的局部变量
function inner() {
const b = 2; // inner的局部变量
console.log(a); // 沿作用域链查找,找到outer中的a → 输出1
}
inner();
}
// 变量提升(Hoisting):var声明会被提升到作用域顶部,但赋值不会
console.log(a); // undefined(声明被提升,但此时还未赋值)
var a = 1;
// let/const 暂时性死区(TDZ):在声明前访问会报错,比var更安全
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 2;
2. 闭包(Closure)¶
JavaScript
// 闭包的本质:函数+词法环境(函数能记住并访问其定义时的作用域)
function createCounter() {
let count = 0; // 自由变量:被内部函数引用,不会被垃圾回收
// 返回的对象中的方法都共享同一个count变量(形成闭包)
return {
increment: function() {
count++; // 通过闭包访问并修改count
return count;
},
decrement: function() {
count--;
return count;
},
getCount: function() {
return count; // 通过闭包读取count的当前值
}
};
}
const counter = createCounter(); // 创建一个独立的计数器实例
console.log(counter.increment()); // 1(count从0变为1)
console.log(counter.increment()); // 2(count从1变为2)
console.log(counter.getCount()); // 2(读取当前count值)
// 注意:外部无法直接访问count变量,实现了数据私有化
// 实际应用:模块化模式(IIFE + 闭包实现私有成员)
const Module = (function() {
// 私有变量和方法:外部无法直接访问
let privateVar = 0;
function privateMethod() {
console.log('Private method');
}
// 只暴露公共接口,隐藏内部实现细节
return {
publicMethod: function() {
privateVar++; // 通过闭包访问私有变量
privateMethod(); // 通过闭包调用私有方法
console.log('Public method', privateVar);
}
};
})(); // 立即执行函数表达式(IIFE),执行后返回公共接口对象
Module.publicMethod(); // Private method \n Public method 1
3. 原型链与继承¶
JavaScript
// 原型链的本质:每个对象都有一个内部链接指向其原型对象,形成链式结构
function Person(name) {
this.name = name; // 实例属性:每个实例独有一份
}
// 原型方法:所有实例共享同一份,节省内存
Person.prototype.sayHello = function() {
console.log(`Hello, I'm ${this.name}`);
};
const alice = new Person('Alice');
alice.sayHello(); // Hello, I'm Alice(先在实例上找,找不到则沿原型链向上查找)
// 原型链查找路径:alice → Person.prototype → Object.prototype → null
console.log(alice.__proto__ === Person.prototype); // true(实例的原型指向构造函数的prototype)
console.log(Person.prototype.__proto__ === Object.prototype); // true(所有对象最终继承自Object)
console.log(Object.prototype.__proto__); // null(原型链的终点)
// 手写new操作符——理解new关键字背后的三步操作
function myNew(constructor, ...args) { // ...展开运算符:展开数组/对象
// 第1步:创建空对象,并将其原型指向构造函数的prototype(建立原型链)
const obj = Object.create(constructor.prototype);
// 第2步:执行构造函数,将this绑定到新对象(初始化实例属性)
const result = constructor.apply(obj, args);
// 第3步:如果构造函数显式返回了对象则使用该对象,否则返回新创建的对象
return result instanceof Object ? result : obj;
}
// ES6 Class语法糖——底层仍然基于原型链,但写法更清晰
class Animal {
constructor(name) {
this.name = name; // 构造函数中初始化实例属性
}
speak() { // 定义在prototype上的方法
console.log(`${this.name} makes a sound`);
}
}
// extends实现继承:Dog.prototype.__proto__ === Animal.prototype
class Dog extends Animal {
speak() { // 方法重写(override):子类覆盖父类的同名方法
console.log(`${this.name} barks`);
}
}
const dog = new Dog('Buddy');
dog.speak(); // Buddy barks(调用Dog自身的speak,不会沿原型链找到Animal的)
4. 事件循环(Event Loop)¶
JavaScript
// === 事件循环机制(Event Loop) ===
// 执行顺序:同步代码 → 微任务队列(Promise.then等)→ 宏任务队列(setTimeout等)
console.log('1'); // 【同步】立即执行,进入调用栈
setTimeout(() => {
console.log('2'); // 【宏任务】放入宏任务队列,等待下一轮事件循环
}, 0);
Promise.resolve().then(() => {
console.log('3'); // 【微任务】放入微任务队列,本轮同步代码执行完后立即执行
});
console.log('4'); // 【同步】立即执行
// 输出顺序:1, 4, 3, 2
// 解析:同步(1,4) → 微任务(3) → 宏任务(2)
// === 更复杂的例子:嵌套的宏任务和微任务 ===
console.log('start'); // 【同步】
setTimeout(() => { // 【宏任务1】进入宏任务队列
console.log('setTimeout1');
Promise.resolve().then(() => { // 宏任务1执行时产生的微任务,在该宏任务结束前执行
console.log('promise1');
});
}, 0);
setTimeout(() => { // 【宏任务2】进入宏任务队列(排在宏任务1后面)
console.log('setTimeout2');
}, 0);
Promise.resolve().then(() => { // 【微任务1】进入微任务队列
console.log('promise2');
setTimeout(() => { // 微任务1执行时产生的宏任务,进入宏任务队列
console.log('setTimeout3');
}, 0);
});
console.log('end'); // 【同步】
// 输出:start, end, promise2, setTimeout1, promise1, setTimeout2, setTimeout3
// 解析:同步(start,end) → 微任务(promise2) → 宏任务1(setTimeout1) → 其微任务(promise1) → 宏任务2(setTimeout2) → 宏任务3(setTimeout3)
5. 手写Promise¶
JavaScript
// ========== 手写Promise:完整实现Promises/A+规范 ==========
class MyPromise {
constructor(executor) {
this.state = 'pending'; // Promise三种状态:pending(等待)、fulfilled(成功)、rejected(失败)
this.value = undefined; // 成功时的值
this.reason = undefined; // 失败时的原因
this.onFulfilledCallbacks = []; // 成功回调队列(支持异步场景下多次then调用)
this.onRejectedCallbacks = []; // 失败回调队列
// resolve函数:将状态从pending变为fulfilled
const resolve = (value) => { // 箭头函数:简洁的函数语法
if (this.state === 'pending') { // 状态只能从pending转变,且只能转变一次
this.state = 'fulfilled';
this.value = value;
// 依次执行所有等待中的成功回调(异步resolve场景)
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
// reject函数:将状态从pending变为rejected
const reject = (reason) => { // const不可重新赋值;let块级作用域变量
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
};
// 立即执行executor,捕获同步异常自动reject
try { // try/catch捕获异常
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
// then方法:注册成功和失败的回调,返回新的Promise(实现链式调用)
then(onFulfilled, onRejected) {
// 参数默认值处理:实现值穿透(.then().then(v => ...)仍能拿到值)
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
// 返回新的Promise,实现链式调用的核心
const promise2 = new MyPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
// 用setTimeout模拟微任务,确保异步执行(规范要求)
setTimeout(() => {
try {
const x = onFulfilled(this.value); // 执行成功回调
resolvePromise(promise2, x, resolve, reject); // 处理返回值
} catch (error) {
reject(error); // 回调中抛出的异常传递给下一个Promise
}
}, 0);
} else if (this.state === 'rejected') {
setTimeout(() => {
try {
const x = onRejected(this.reason); // 执行失败回调
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else {
// pending状态:将回调存入队列,等待resolve/reject时执行
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise2; // 返回新Promise,支持 .then().then() 链式调用
}
// catch方法:语法糖,等价于 .then(null, onRejected)
catch(onRejected) {
return this.then(null, onRejected);
}
// 静态方法:快速创建已成功的Promise
static resolve(value) {
return new MyPromise((resolve) => resolve(value));
}
// 静态方法:快速创建已失败的Promise
static reject(reason) {
return new MyPromise((_, reject) => reject(reason));
}
// Promise.all:所有Promise都成功才成功,任一失败则立即失败
static all(promises) {
return new MyPromise((resolve, reject) => {
const results = []; // 存储每个Promise的结果
let count = 0; // 已完成的Promise计数
promises.forEach((promise, index) => {
Promise.resolve(promise).then(value => { // Promise异步操作容器:pending→fulfilled/rejected
results[index] = value; // 按原始顺序存放结果(不是按完成顺序)
count++;
if (count === promises.length) {
resolve(results); // 全部完成,resolve总结果
}
}).catch(reject); // 任一失败,直接reject
});
});
}
}
// Promise解析过程(Resolution Procedure):处理then回调的返回值
// 这是Promises/A+规范的核心,决定了链式调用的行为
function resolvePromise(promise2, x, resolve, reject) {
// 防止循环引用:then回调返回了自身Promise
if (promise2 === x) {
reject(new TypeError('Chaining cycle detected'));
return;
}
// 如果x是对象或函数,尝试将其作为thenable处理
if (x && (typeof x === 'object' || typeof x === 'function')) {
let called = false; // 防止resolve和reject被多次调用
try {
const then = x.then;
if (typeof then === 'function') {
// x是thenable(含then方法的对象/函数),递归解析
then.call(x, y => {
if (called) return; // 确保只调用一次
called = true;
resolvePromise(promise2, y, resolve, reject); // 递归处理(y可能还是Promise)
}, r => {
if (called) return;
called = true;
reject(r);
});
} else {
resolve(x); // x有then属性但不是函数,直接resolve
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
resolve(x); // x是普通值(非对象非函数),直接resolve
}
}
// ========== 测试 ==========
const p = new MyPromise((resolve, reject) => {
setTimeout(() => resolve('Success!'), 1000); // 1秒后异步resolve
});
// 链式调用:每个then返回新的Promise
p.then(value => {
console.log(value); // 输出:Success!
return 'Next value'; // 返回值会传递给下一个then
}).then(value => {
console.log(value); // 输出:Next value
});
✅ 学习检查点¶
- 理解执行上下文和作用域链
- 能解释闭包的原理和应用
- 理解原型链和继承机制
- 能解释事件循环机制
- 能手写Promise实现
记住:JavaScript是前端的基础,深入理解它才能掌握框架原理! 📚