JS 函数偷偷卷的小秘密:闭包魔法 + 柯里化收集术被我扒光啦~૮(˃ ⤙ ˂)و

5 阅读4分钟

从闭包到柯里化:JS 函数进阶实战指南(超易懂版~)

一、闭包:JS 函数的 “记忆魔法”

(一)闭包是什么?

闭包就是一个函数可以访问并记住外层函数作用域的变量~简单来说,就是 “函数嵌套函数,内层函数引用外层变量”。比如:

function outer() {
  let count = 0;
  function inner() {
    count++; // 记住了外层的count变量
    console.log(count);
  }
  return inner;
}
const counter = outer();
counter(); // 1
counter(); // 2

就像内层函数带了一个 “小书包”,把外层的变量都装进去啦~

(二)闭包的核心原理

  1. 词法作用域嵌套:函数定义时确定作用域链,内层函数可以访问外层函数的变量
  2. 引用保持:外层函数执行完后,变量不会被销毁,因为内层函数还在引用它
  3. 闭包三要素:函数嵌套 + 内层引用外层变量 + 外层返回内层函数

(三)闭包的实用场景

  • 封装私有变量:像银行账户,外部只能通过特定方法操作余额
  • 防抖节流:表单搜索时,等用户输入完再触发查询(超实用的性能优化技巧哦~)
  • 函数柯里化:后面会重点讲!先记住它需要闭包来收集参数

二、函数拆解:JS 函数的十八般武艺

(一)函数是一等公民

在 JS 里,函数和数字、字符串一样,可以:

  • 赋值给变量:const fn = function() {}
  • 作为参数传递:arr.map(function(item) {})
  • 作为返回值:function outer() { return function() {} }

(二)函数的多样形态

  1. 匿名函数 & 立即执行函数(IIFE)
    匿名函数没有名字,常用来做回调;IIFE 定义后立即执行,比如:

    (function() {
      console.log("我是立即执行的~");
    })();
    
  2. 箭头函数 vs 传统函数
    箭头函数更简洁,而且this指向定义时的作用域(再也不用担心this乱跑啦~):

    const arrowFn = (a, b) => a + b; // 一行代码直接返回
    
  3. 递归函数
    自己调用自己,适合解决分治问题,比如计算阶乘:

    function factorial(n) {
      return n === 0 ? 1 : n * factorial(n - 1);
    }
    

三、柯里化:让函数参数 “慢慢来”

(一)柯里化是什么?

把一个多参数函数变成多个单参数函数的嵌套~比如:

// 普通函数
add(1, 2, 3); // 直接传3个参数

// 柯里化后
const addCurry = curry(add);
addCurry(1)(2)(3); // 分3次传参,最后计算结果

就像收集龙珠,每次收集一个参数,凑够了就召唤神龙(执行函数)!

(二)手写一个万能 curry 函数

核心思路:

  1. 记住原函数需要的参数个数(fn.length

  2. 每次调用收集参数,直到参数够了就执行原函数

  3. 用闭包保存已收集的参数

function curry(fn) {
  // 收集参数的“小仓库”
  const argsList = [];
  return function judge(...newArgs) {
    argsList.push(...newArgs);
    // 凑够参数就执行
    if (argsList.length >= fn.length) {
      return fn(...argsList);
    }
    // 不够的话继续返回收集函数
    return judge;
  };
}

// 测试一下
function add(a, b, c) {
  return a + b + c;
}
const addCurry = curry(add);
console.log(addCurry(1)(2)(3)); // 6,成功啦!

(三)柯里化的优势

  • 参数复用:比如固定请求的基础参数,后面只传变化的部分
  • 函数拆分:把复杂函数拆成简单的单参数函数,更易维护
  • 逻辑清晰:每次只关心一个参数,代码可读性 UP!

四、避坑指南:闭包与柯里化的正确打开方式

(一)闭包的内存问题

  • 不要滥用闭包,避免大量变量无法释放
  • 不用时及时释放引用:closure = null;

(二)柯里化的参数匹配

  • 注意原函数的参数个数(fn.length)要准确
  • 支持传多个参数:比如addCurry(1, 2)(3)也是可以的哦~

(三)代码规范建议

  • 复杂逻辑加注释,比如 curry 函数的参数收集过程
  • 保持函数单一职责,柯里化函数只负责参数收集

总结:从基础到进阶的函数之旅

闭包就像函数的 “记忆魔法”,让内层函数能记住外层的变量;
柯里化则是参数的 “收集器”,让函数调用更灵活~
掌握这些进阶技巧,写代码时就能像搭积木一样轻松组合功能啦!
下次遇到复杂函数场景,记得试试闭包和柯里化哦,说不定会有惊喜~🤓