三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE

我如何用费曼学习法三个月搞懂闭包

从死记"函数嵌函数"到能给别人讲清楚作用域链——这套方法救了我对 JavaScript 最头疼的概念。

我如何用费曼学习法三个月搞懂闭包

闭包是我学 JavaScript 时卡得最久的一个概念。第一次看到"函数嵌函数、外层变量被内层引用"这种描述时,我能背下来,但写代码时却完全不知道它到底在解决什么问题。直到我换了学习方法——费曼学习法,整整三个月,我才算真正把它内化成自己的东西。这篇文章记录的是我完整的过程,希望对同样卡在闭包上的你有用。

费曼学习法实践笔记与代码练习

一、学习背景:为什么我卡在闭包

我最早接触闭包是在一本 JavaScript 入门书里。书里说:"闭包是函数和声明该函数的词法环境的组合。"我盯着这句话看了十分钟,把每个字都认得了,合起来却像天书。后来我又去搜博客,看到"作用域链""变量驻留""内存泄漏"这些词,越看越乱。

问题不在我笨,而在我只是在"接收"知识,没有在"重构"知识。我能复述定义,却没法用自己的话讲给一个完全不懂编程的人听。这正是费曼学习法的核心痛点:如果你讲不明白,就说明你没真正懂。

二、费曼法四步实践

费曼学习法说起来很简单,就四步,但每一步都极费心力。我把这四步套在闭包上试了整整三个月。

第一步:选定概念,写在纸上

我在 A4 纸顶端写下"闭包"两个字,然后逼自己用一句大白话写下它是什么。第一版写的是:"函数里面再套一个函数。"——这显然不对,这只是嵌套调用,根本没说清闭包的本质。但写下来这个错误版本很重要,它让我看到了自己的盲区。

第二步:用大白话讲给一个假想的人听

我假装在给完全没学过编程的朋友讲。一开始我讲:"闭包就是函数记住它出生时周围的变量。"朋友反问:"函数又不是人,怎么记住?"我卡住了。这个卡住的瞬间,就是费曼法的价值所在——它精准地戳出了我没理解的那一层。

第三步:讲不明白就回去补

既然"记住"这个词讲不通,我就回去补词法作用域、执行上下文、变量对象这些底层概念。补完之后再讲,第二版变成了:"函数在创建时,会把它能访问的变量打包带走,哪怕这些变量所在的函数已经执行完返回了,它们依然活着。"这一版朋友听懂了,我也松了口气。

第四步:简化再简化,直到能举例

最后一步是把它简化成能举出例子的话。我举的例子是:一个计数器函数,每次调用返回的内部函数,计数都会累加。这就是闭包最经典的场景。能举出例子,才说明概念真的落地了。

如果你不能用一句话讲清一个概念,并给一个最小例子,那它对你来说还是别人的知识,不是你的。

三、最终理解闭包

三个月后,我对闭包的理解收敛成了这样一句话:闭包是一个函数对其定义时所在作用域变量的持续引用,使得这些变量不会随外层函数返回而被回收。它解决了"如何在函数外部安全地访问和修改函数内部状态"的问题,是模块化、私有变量、回调状态保存的基石。

理解到这一层后,再去看 React 的 useState、去看节流防抖、去看事件监听里的状态保持,全都通了——它们本质上都在用闭包。

四、附:闭包示例代码

下面是我用来反复验证理解的那个最小例子,一个计数器:

function createCounter() {
  let count = 0;            // 外层函数的局部变量
  return function() {      // 内层函数引用了 count,形成闭包
    count += 1;
    return count;
  };
}

const next = createCounter();
console.log(next()); // 1
console.log(next()); // 2
console.log(next()); // 3

createCounter 执行完返回后,按理 count 应该被销毁。但因为返回的内部函数引用了它,count 被保留了下来,每次调用 next 都在访问同一个 count。这就是闭包在做的事。

五、写在最后

三个月听起来很长,但这三个月里我顺便把作用域、执行上下文、this、原型链都串起来了,因为我每讲不清一个点就回去补,补着补着就把整张图补全了。费曼学习法的真正价值,不是让你学得更快,而是让你诚实地面对自己"哪里没懂"。

如果你也卡在某个概念上,别急着换教程,先拿出一张纸,试着用大白话讲一遍。讲不通的地方,就是你要去补的地方。

← 返回学习日记