JavaScript进阶:手写实现10个高频工具函数详解
2025.09.19 12:56浏览量:0简介:本文深度解析JavaScript进阶阶段必须掌握的10个核心工具函数的手写实现,涵盖数组处理、函数式编程、异步控制等场景,通过原理剖析和代码示例帮助开发者突破原生API依赖,提升代码掌控力。
JavaScript进阶:手写实现10个高频工具函数详解
在JavaScript开发中,过度依赖第三方库会导致代码体积膨胀和性能损耗。本文将系统讲解10个进阶场景下必须掌握的核心工具函数的手写实现,涵盖数组处理、函数式编程、异步控制等关键领域,帮助开发者建立扎实的底层实现能力。
一、数组扁平化处理(flatten)
1.1 递归实现方案
function flatten(arr) {
let result = [];
for (const item of arr) {
if (Array.isArray(item)) {
result = result.concat(flatten(item));
} else {
result.push(item);
}
}
return result;
}
// 测试用例
console.log(flatten([1, [2, [3, 4]], 5])); // [1, 2, 3, 4, 5]
1.2 迭代实现方案
function flattenIterative(arr) {
const stack = [...arr];
const result = [];
while (stack.length) {
const next = stack.pop();
if (Array.isArray(next)) {
stack.push(...next);
} else {
result.push(next);
}
}
return result.reverse();
}
1.3 深度控制实现
function flattenDeep(arr, depth = 1) {
return depth > 0
? arr.reduce((prev, curr) =>
prev.concat(Array.isArray(curr)
? flattenDeep(curr, depth - 1)
: curr), [])
: arr.slice();
}
二、函数柯里化(Currying)
2.1 基础柯里化实现
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2));
}
}
}
}
// 使用示例
const sum = (a, b, c) => a + b + c;
const curriedSum = curry(sum);
console.log(curriedSum(1)(2)(3)); // 6
2.2 带占位符的柯里化
function curryWithPlaceholder(fn) {
const placeholder = Symbol();
const curried = (...args) => {
const filledArgs = args.map(arg =>
arg === placeholder ? undefined : arg
);
const missingArgs = fn.length - filledArgs.filter(Boolean).length;
if (missingArgs <= 0) {
return fn(...filledArgs);
} else {
return (...newArgs) => {
const newArgsWithPlaceholders = newArgs.map(arg =>
arg === placeholder ? placeholder : arg
);
const combinedArgs = args.map((arg, i) =>
arg === placeholder ? newArgsWithPlaceholders.shift() || placeholder : arg
);
return curried(...combinedArgs);
}
}
};
curried.placeholder = placeholder;
return curried;
}
三、防抖与节流(Debounce & Throttle)
3.1 防抖函数实现
function debounce(fn, delay, immediate = false) {
let timer = null;
return function(...args) {
const context = this;
if (timer) clearTimeout(timer);
if (immediate && !timer) {
fn.apply(context, args);
}
timer = setTimeout(() => {
if (!immediate) {
fn.apply(context, args);
}
timer = null;
}, delay);
}
}
// 使用场景
window.addEventListener('resize', debounce(() => {
console.log('Window resized');
}, 300));
3.2 节流函数实现
function throttle(fn, delay) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= delay) {
fn.apply(this, args);
lastTime = now;
}
}
}
// 时间戳版改进
function throttleAdvanced(fn, delay) {
let lastTime = 0;
let timer = null;
return function(...args) {
const now = Date.now();
const remaining = delay - (now - lastTime);
if (remaining <= 0) {
if (timer) {
clearTimeout(timer);
timer = null;
}
lastTime = now;
fn.apply(this, args);
} else if (!timer) {
timer = setTimeout(() => {
lastTime = Date.now();
timer = null;
fn.apply(this, args);
}, remaining);
}
}
}
四、Promise并行控制(Promise.all变体)
4.1 限制并发数的Promise调度器
class PromiseScheduler {
constructor(maxConcurrent = 3) {
this.maxConcurrent = maxConcurrent;
this.running = 0;
this.queue = [];
}
add(promiseCreator) {
return new Promise((resolve, reject) => {
this.queue.push({ promiseCreator, resolve, reject });
this.run();
});
}
run() {
while (this.running < this.maxConcurrent && this.queue.length) {
const { promiseCreator, resolve, reject } = this.queue.shift();
this.running++;
promiseCreator()
.then(resolve)
.catch(reject)
.finally(() => {
this.running--;
this.run();
});
}
}
}
// 使用示例
const scheduler = new PromiseScheduler(2);
const tasks = Array(5).fill(0).map((_, i) =>
() => new Promise(res => setTimeout(() => {
console.log(`Task ${i} completed`);
res(i);
}, Math.random() * 1000))
);
tasks.forEach(task => scheduler.add(task));
4.2 带超时控制的Promise.all
function promiseAllWithTimeout(promises, timeout) {
return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
reject(new Error('Promise.all timeout'));
}, timeout);
Promise.all(promises)
.then(resolve)
.catch(reject)
.finally(() => {
clearTimeout(timeoutId);
});
});
}
五、深拷贝实现(Deep Clone)
5.1 完整深拷贝实现
function deepClone(obj, hash = new WeakMap()) {
// 处理基本类型和null/undefined
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 处理循环引用
if (hash.has(obj)) {
return hash.get(obj);
}
// 处理Date和RegExp
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
// 处理Map和Set
if (obj instanceof Map) {
const clone = new Map();
hash.set(obj, clone);
obj.forEach((value, key) => {
clone.set(deepClone(key, hash), deepClone(value, hash));
});
return clone;
}
if (obj instanceof Set) {
const clone = new Set();
hash.set(obj, clone);
obj.forEach(value => {
clone.add(deepClone(value, hash));
});
return clone;
}
// 处理普通对象和数组
const cloneObj = Array.isArray(obj) ? [] : {};
hash.set(obj, cloneObj);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepClone(obj[key], hash);
}
}
// 处理Symbol属性
const symbolKeys = Object.getOwnPropertySymbols(obj);
for (const symKey of symbolKeys) {
cloneObj[symKey] = deepClone(obj[symKey], hash);
}
return cloneObj;
}
六、函数组合(Function Composition)
6.1 从右到左的组合实现
function compose(...fns) {
return function(initialValue) {
return fns.reduceRight((acc, fn) => fn(acc), initialValue);
}
}
// 使用示例
const add5 = x => x + 5;
const multiplyBy2 = x => x * 2;
const subtract3 = x => x - 3;
const composedFn = compose(subtract3, multiplyBy2, add5);
console.log(composedFn(10)); // (10+5)*2-3 = 27
6.2 从左到右的组合实现
function pipe(...fns) {
return function(initialValue) {
return fns.reduce((acc, fn) => fn(acc), initialValue);
}
}
// 与compose的对比
const pipedFn = pipe(add5, multiplyBy2, subtract3);
console.log(pipedFn(10)); // ((10+5)*2)-3 = 27
七、发布订阅模式(Pub/Sub)
7.1 基础实现
class EventEmitter {
constructor() {
this.events = {};
}
on(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
emit(event, ...args) {
if (this.events[event]) {
this.events[event].forEach(callback => {
callback.apply(this, args);
});
}
}
off(event, callback) {
if (!this.events[event]) return;
if (!callback) {
delete this.events[event];
} else {
this.events[event] = this.events[event].filter(
cb => cb !== callback
);
}
}
once(event, callback) {
const onceWrapper = (...args) => {
callback.apply(this, args);
this.off(event, onceWrapper);
};
this.on(event, onceWrapper);
}
}
// 使用示例
const emitter = new EventEmitter();
const handler = data => console.log('Received:', data);
emitter.on('message', handler);
emitter.emit('message', 'Hello'); // Received: Hello
emitter.off('message', handler);
emitter.emit('message', 'World'); // 无输出
八、惰性函数(Lazy Evaluation)
8.1 惰性求值实现
function createLazyFunction(fn) {
let cache = null;
return function(...args) {
if (cache === null) {
cache = fn.apply(this, args);
}
return cache;
}
}
// 使用示例
const expensiveCalculation = createLazyFunction(() => {
console.log('Performing expensive calculation...');
return Math.random();
});
console.log(expensiveCalculation()); // 输出日志并返回随机数
console.log(expensiveCalculation()); // 直接返回缓存值
8.2 惰性链式调用
class LazyChain {
constructor(value) {
this._calls = [];
this._value = value;
}
through(fn) {
this._calls.push(fn);
return this;
}
value() {
return this._calls.reduce((val, fn) => fn(val), this._value);
}
static of(value) {
return new LazyChain(value);
}
}
// 使用示例
const result = LazyChain.of([1, 2, 3])
.through(arr => arr.map(x => x * 2))
.through(arr => arr.filter(x => x > 3))
.value(); // [4, 6]
九、观察者模式(Observer Pattern)
9.1 可观察对象实现
class Observable {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
return {
unsubscribe: () => {
this.observers = this.observers.filter(
obs => obs !== observer
);
}
};
}
notify(data) {
this.observers.forEach(observer => {
if (typeof observer.update === 'function') {
observer.update(data);
}
});
}
}
// 使用示例
const observable = new Observable();
const observer1 = {
update: data => console.log('Observer1:', data)
};
const observer2 = {
update: data => console.log('Observer2:', data)
};
const subscription1 = observable.subscribe(observer1);
const subscription2 = observable.subscribe(observer2);
observable.notify('Test message');
subscription1.unsubscribe();
observable.notify('Another message');
十、记忆化(Memoization)
10.1 基础记忆化实现
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
}
}
// 使用示例
const factorial = memoize(n => {
if (n <= 1) return 1;
return n * factorial(n - 1);
});
console.log(factorial(5)); // 计算并缓存
console.log(factorial(5)); // 从缓存获取
10.2 带过期时间的记忆化
function memoizeWithExpiry(fn, ttl) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
const now = Date.now();
// 检查缓存是否存在且未过期
if (cache.has(key)) {
const { value, expiry } = cache.get(key);
if (now < expiry) {
return value;
}
cache.delete(key);
}
const result = fn.apply(this, args);
cache.set(key, {
value: result,
expiry: now + ttl
});
return result;
}
}
// 使用示例
const expensiveOperation = memoizeWithExpiry(
() => {
console.log('Performing expensive operation...');
return Math.random();
},
5000 // 5秒过期
);
性能优化建议
缓存策略:对于记忆化函数,根据数据特性选择合适的缓存键生成方式,复杂对象建议使用JSON.stringify或自定义序列化方法
错误处理:在防抖/节流函数中添加错误边界处理,防止意外错误导致定时器无法清除
内存管理:对于事件发射器,定期清理不再使用的事件监听器,避免内存泄漏
类型检查:在深拷贝实现中增加更严格的类型检查,防止意外行为
并发控制:Promise调度器可根据实际需求调整队列策略(FIFO/LIFO)
总结
本文系统讲解了10个进阶JavaScript工具函数的手写实现,涵盖从基础数组操作到复杂异步控制的各种场景。这些实现不仅帮助开发者理解底层原理,更能在实际项目中减少对第三方库的依赖,提升代码性能和可维护性。建议开发者在实践中逐步掌握这些模式,并根据具体需求进行定制化改造。
发表评论
登录后可评论,请前往 登录 或 注册