JavaScript闭包怎样实现部分应用

来源:编程网作者:叶知晏头衔:草根站长
导读:本期聚焦于小伙伴创作的《JavaScript闭包怎样实现部分应用》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《JavaScript闭包怎样实现部分应用》有用,将其分享出去将是对创作者最好的鼓励。

部分应用是函数式编程里的常见操作,核心逻辑是固定一个函数的部分参数,生成一个接收剩余参数的新函数,减少重复传参的同时提升代码复用性。JavaScript的闭包特性可以完美支撑这种实现,因为闭包能保存外层函数的作用域变量,让固定下来的参数在后续调用时依然可用。

JavaScript闭包怎样实现部分应用

核心概念铺垫

什么是闭包

闭包指的是函数可以访问其词法作用域之外的变量,即使外层函数已经执行完毕,这些变量依然会被保留。简单来说,当一个函数内部返回另一个函数,内部函数引用了外层函数的变量,就形成了闭包。

什么是部分应用

部分应用和柯里化容易混淆,柯里化是把多参数函数转成一系列单参数函数,而部分应用是固定任意数量的参数,返回接收剩余参数的函数。比如一个接收三个参数的函数,固定前两个参数,返回的函数只需要接收第三个参数即可执行。

基础实现:固定单个参数

我们先从一个简单的加法函数入手,实现固定其中一个参数的部分应用。假设我们有一个计算两个数之和的函数:

function add(a, b) {
  return a + b;
}

现在我们想固定第一个参数为5,生成一个加5的函数,用闭包实现如下:

function partialAdd(a) {
  // 闭包保存了传入的a的值
  return function(b) {
    return add(a, b);
  };
}

// 生成固定第一个参数为5的新函数
const addFive = partialAdd(5);
// 调用新函数,只需要传剩余参数
console.log(addFive(3)); // 输出8
console.log(addFive(10)); // 输出15

这里partialAdd执行后返回的内部函数形成了闭包,保存了传入的a的值,后续调用addFive的时候,依然能拿到之前传入的5,完成加法运算。

通用实现:支持任意参数固定

上面的例子只能固定第一个参数,实际场景中我们可能需要固定任意位置的参数,或者固定多个参数。我们可以实现一个通用的部分应用函数,接收原始函数和部分参数,返回接收剩余参数的新函数。

/**
 * 通用部分应用实现
 * @param {Function} fn 原始函数
 * @param  {...any} fixedArgs 要固定的参数
 * @returns {Function} 接收剩余参数的新函数
 */
function partial(fn, ...fixedArgs) {
  return function(...remainingArgs) {
    // 合并固定参数和剩余参数,按顺序传入原始函数
    return fn.apply(this, fixedArgs.concat(remainingArgs));
  };
}

这个实现的核心是利用闭包保存传入的fnfixedArgs,返回的内部函数接收剩余参数后,把两部分参数合并传给原始函数执行。我们来看几个使用场景:

场景1:固定前两个参数

function multiply(a, b, c) {
  return a * b * c;
}

// 固定前两个参数为2和3
const multiplyTwoAndThree = partial(multiply, 2, 3);
console.log(multiplyTwoAndThree(4)); // 2*3*4=24
console.log(multiplyTwoAndThree(5)); // 2*3*5=30

场景2:固定中间参数

如果需要固定中间位置的参数,我们可以用undefined占位,调用的时候再传入对应位置的参数:

// 固定第二个参数为10,第一个和第三个参数后续传入
const partialMultiply = partial(multiply, undefined, 10);
// 第一个参数传2,剩余参数传3,对应第三个参数
console.log(partialMultiply(2, 3)); // 2*10*3=60

实际应用示例

部分应用在实际开发中非常实用,比如处理事件监听的时候固定部分参数,或者处理接口请求的时候固定基础配置。

事件监听场景

假设我们有一个处理点击的函数,需要传入事件对象和额外的配置参数:

function handleClick(config, event) {
  console.log('配置:', config);
  console.log('点击事件:', event);
}

// 固定配置参数
const handleClickWithConfig = partial(handleClick, { theme: 'dark', lang: 'zh' });

// 给按钮添加点击事件,只需要传事件对象
document.getElementById('btn').addEventListener('click', handleClickWithConfig);

接口请求场景

封装请求函数的时候,固定基础路径和请求头:

function request(baseUrl, headers, url, data) {
  return fetch(baseUrl + url, {
    method: 'POST',
    headers: headers,
    body: JSON.stringify(data)
  }).then(res => res.json());
}

// 固定基础路径和请求头
const apiRequest = partial(request, 'https://ipipp.com/api', {
  'Content-Type': 'application/json',
  'Token': 'test_token'
});

// 调用的时候只需要传接口路径和参数
apiRequest('/user/list', { page: 1 }).then(data => console.log(data));

注意事项

  • 闭包会保存外层变量,如果固定的参数占用内存较大,或者部分应用生成的函数长期不被释放,可能会造成内存占用过高,需要根据场景合理使用。
  • 通用实现中参数合并是按顺序拼接的,如果需要更复杂的参数占位逻辑,可以在通用函数里增加占位符判断,比如用partial函数接收特殊占位符,在合并参数的时候替换成剩余参数。
  • 部分应用生成的新函数的this指向可以通过apply或者call调整,上面的通用实现里用了apply把内部函数的this传给原始函数,避免this指向丢失的问题。

JavaScript闭包部分应用函数式编程修改时间:2026-07-13 16:06:45

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。