JavaScript进阶:手写实现10个核心高阶函数
2025.09.19 12:47浏览量:0简介:本文深入解析JavaScript进阶开发中必须掌握的10个核心高阶函数的手写实现,涵盖函数式编程、异步控制、数据结构等关键领域,提供可复用的代码模板和性能优化方案。
一、函数式编程核心:柯里化与反柯里化
1.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 add = curry((a, b, c) => a + b + c);
console.log(add(1)(2)(3)); // 6
console.log(add(1, 2)(3)); // 6
关键点:通过fn.length
判断参数是否收集完毕,利用闭包保存中间状态。性能优化可添加缓存机制,避免重复创建函数。
1.2 反柯里化实现
反柯里化将方法从特定对象解耦,增强通用性:
function unCurry(fn) {
return function(obj, ...args) {
return fn.apply(obj, args);
}
}
const push = unCurry(Array.prototype.push);
let obj = { length: 0 };
push(obj, 1, 2, 3);
console.log(obj); // { '0': 1, '1': 2, '2': 3, length: 3 }
应用场景:当需要将对象方法作为通用函数使用时,如实现跨类型操作。
二、异步控制进阶:Promise与Generator
2.1 手写Promise实现
完整实现需包含状态管理、链式调用和异常处理:
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
// 实现链式调用...
}
}
核心机制:状态机管理(pending→fulfilled/rejected)、微任务队列模拟(可用setTimeout替代)、值穿透处理。
2.2 Generator自动执行器
将Generator函数转换为类似async/await的语法:
function co(gen) {
return new Promise((resolve, reject) => {
const iterator = gen();
function step(nextFn) {
try {
const { value, done } = nextFn();
if (done) return resolve(value);
Promise.resolve(value).then(
v => step(() => iterator.next(v)),
e => step(() => iterator.throw(e))
);
} catch (err) {
reject(err);
}
}
step(() => iterator.next());
});
}
// 使用示例
co(function* () {
const a = yield Promise.resolve(1);
const b = yield Promise.resolve(a + 1);
return b;
}).then(console.log); // 2
实现要点:递归执行Generator、自动处理Promise、错误传播机制。
三、数据结构操作:深度克隆与扁平化
3.1 深度克隆实现
处理循环引用、特殊对象(Date、RegExp等)和Symbol属性:
function deepClone(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (hash.has(obj)) return hash.get(obj);
let clone;
if (obj instanceof Date) clone = new Date(obj);
else if (obj instanceof RegExp) clone = new RegExp(obj);
else {
clone = Array.isArray(obj) ? [] : {};
hash.set(obj, clone);
Reflect.ownKeys(obj).forEach(key => {
if (typeof key === 'symbol') {
clone[key] = deepClone(obj[key], hash);
} else {
clone[key] = deepClone(obj[key], hash);
}
});
}
return clone;
}
关键处理:使用WeakMap解决循环引用,Reflect.ownKeys获取所有属性(包括不可枚举和Symbol)。
3.2 数组扁平化实现
支持指定深度和自动判断深度:
function flatten(arr, depth = Infinity) {
let result = [];
for (const item of arr) {
if (Array.isArray(item) && depth > 0) {
result.push(...flatten(item, depth - 1));
} else {
result.push(item);
}
}
return result;
}
// 使用示例
console.log(flatten([1, [2, [3, [4]]]], 2)); // [1, 2, 3, [4]]
性能优化:使用展开运算符替代concat,减少中间数组创建。
四、高阶工具函数:组合与管道
4.1 函数组合实现
从右到左执行函数:
function compose(...fns) {
return function(arg) {
return fns.reduceRight((prev, fn) => fn(prev), arg);
}
}
// 使用示例
const add5 = x => x + 5;
const multiply2 = x => x * 2;
const result = compose(multiply2, add5)(10); // 30
4.2 管道函数实现
从左到右执行函数:
function pipe(...fns) {
return function(arg) {
return fns.reduce((prev, fn) => fn(prev), arg);
}
}
// 使用示例
const result = pipe(add5, multiply2)(10); // 30
应用场景:构建数据处理流水线,提升代码可读性。
五、性能优化技巧
- 尾递归优化:对于支持ES6的环境,使用尾调用形式避免栈溢出
- 记忆化缓存:为计算密集型函数添加缓存
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;
}
}
惰性求值:延迟计算直到真正需要
function lazy(fn) {
let executed = false;
let result;
return function() {
if (!executed) {
result = fn.apply(this, arguments);
executed = true;
}
return result;
}
}
六、实际应用建议
- 测试驱动开发:为每个手写函数编写单元测试
// 示例测试用例
describe('deepClone', () => {
it('should clone object with circular reference', () => {
const obj = { a: 1 };
obj.self = obj;
const clone = deepClone(obj);
expect(clone).not.toBe(obj);
expect(clone.self).toBe(clone);
});
});
- 性能基准测试:使用
console.time()
对比原生方法 - 渐进式重构:先实现基础版本,再逐步优化
七、常见问题解决方案
- this绑定问题:在柯里化时保留原始this
function bindThis(fn, context) {
return function(...args) {
return fn.apply(context, args);
}
}
- 参数顺序处理:实现部分应用时保持参数灵活性
function partial(fn, ...presetArgs) {
return function(...laterArgs) {
const args = [...presetArgs, ...laterArgs];
return fn.apply(this, args);
}
}
- 异步错误处理:完善Promise的catch链
通过系统掌握这些核心函数的手写实现,开发者能够深入理解JavaScript底层机制,提升代码质量和开发效率。建议从简单函数开始实践,逐步构建自己的工具库,最终达到灵活运用函数式编程解决复杂问题的水平。
发表评论
登录后可评论,请前往 登录 或 注册