2026-01-19 09:43:07 +08:00

227 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# JS 基础与手写实现
## 1. 手写 Promise
> **场景**:理解异步编程核心机制,处理 Ajax 请求、文件读取、定时器等异步操作的链式调用和错误处理。
> **解决**:回调地狱问题,提供优雅的异步流程控制。
```js
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.callbacks = [];
const resolve = (value) => {
if (this.state !== 'pending') return;
this.state = 'fulfilled';
this.value = value;
this.callbacks.forEach(cb => cb.onFulfilled(value));
};
const reject = (reason) => {
if (this.state !== 'pending') return;
this.state = 'rejected';
this.value = reason;
this.callbacks.forEach(cb => cb.onRejected(reason));
};
try { executor(resolve, reject); } catch (e) { reject(e); }
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
const handle = (callback, fallback) => {
try {
const result = (callback || fallback)(this.value);
result instanceof MyPromise ? result.then(resolve, reject) : resolve(result);
} catch (e) { reject(e); }
};
if (this.state === 'fulfilled') handle(onFulfilled, v => v);
else if (this.state === 'rejected') handle(onRejected, e => { throw e; });
else this.callbacks.push({
onFulfilled: () => handle(onFulfilled, v => v),
onRejected: () => handle(onRejected, e => { throw e; })
});
});
}
}
```
## 2. Promise.all / Promise.race
> **场景**`Promise.all` 用于并行请求多个接口后统一处理(如同时加载用户信息和订单列表);`Promise.race` 用于请求超时控制、竞速取最快响应。
> **解决**:多异步任务协调与超时兜底问题。
```js
// Promise.all - 所有成功才成功
Promise.myAll = (promises) => {
return new Promise((resolve, reject) => {
const results = [];
let count = 0;
promises.forEach((p, i) => {
Promise.resolve(p).then(val => {
results[i] = val;
if (++count === promises.length) resolve(results);
}, reject);
});
});
};
// Promise.race - 第一个完成就返回
Promise.myRace = (promises) => {
return new Promise((resolve, reject) => {
promises.forEach(p => Promise.resolve(p).then(resolve, reject));
});
};
```
## 3. 防抖与节流
> **场景**:防抖用于搜索框输入(停止输入后才请求)、窗口 resize 结束后计算布局;节流用于滚动事件监听、按钮防重复点击。
> **解决**:高频事件触发导致的性能问题和重复请求。
```js
// 防抖:停止触发后执行
function debounce(fn, delay) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 节流:固定间隔执行
function throttle(fn, delay) {
let last = 0;
return function(...args) {
const now = Date.now();
if (now - last >= delay) {
last = now;
fn.apply(this, args);
}
};
}
```
## 4. 深拷贝(处理循环引用)
> **场景**Redux/Vuex 状态管理中复制 state、表单数据备份与重置、避免修改原始数据造成副作用。
> **解决**:引用类型浅拷贝导致的数据污染问题,特别是循环引用场景。
```js
function deepClone(obj, map = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
if (map.has(obj)) return map.get(obj); // 处理循环引用
const clone = Array.isArray(obj) ? [] : {};
map.set(obj, clone);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], map);
}
}
return clone;
}
```
## 5. 函数柯里化
> **场景**:参数复用(如日志函数固定模块名)、延迟执行、函数式编程中的组合与管道操作。
> **解决**:减少重复传参,提高函数复用性和可读性。
```js
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
}
return (...nextArgs) => curried(...args, ...nextArgs);
};
}
// 使用示例
const add = (a, b, c) => a + b + c;
const curriedAdd = curry(add);
curriedAdd(1)(2)(3); // 6
curriedAdd(1, 2)(3); // 6
```
## 6. call / apply / bind 实现
> **场景**改变函数执行上下文如借用数组方法处理类数组、React 类组件中绑定事件处理函数的 this。
> **解决**this 指向问题,实现函数借用和预设参数。
```js
// call
Function.prototype.myCall = function(ctx, ...args) {
ctx = ctx || window;
const key = Symbol();
ctx[key] = this;
const result = ctx[key](...args);
delete ctx[key];
return result;
};
// apply
Function.prototype.myApply = function(ctx, args = []) {
ctx = ctx || window;
const key = Symbol();
ctx[key] = this;
const result = ctx[key](...args);
delete ctx[key];
return result;
};
// bind
Function.prototype.myBind = function(ctx, ...args) {
const fn = this;
return function(...newArgs) {
return fn.apply(ctx, [...args, ...newArgs]);
};
};
```
## 7. 事件总线 EventEmitter
> **场景**:组件间通信(如 Vue 的 EventBus、插件系统、微前端应用间消息传递、解耦模块依赖。
> **解决**:发布-订阅模式实现松耦合的事件驱动架构。
```js
class EventEmitter {
constructor() {
this.events = {};
}
on(event, listener) {
(this.events[event] ||= []).push(listener);
return this;
}
off(event, listener) {
if (this.events[event]) {
this.events[event] = this.events[event].filter(l => l !== listener);
}
return this;
}
emit(event, ...args) {
(this.events[event] || []).forEach(listener => listener(...args));
return this;
}
once(event, listener) {
const wrapper = (...args) => {
listener(...args);
this.off(event, wrapper);
};
return this.on(event, wrapper);
}
}
```