You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript闭包与作用域疑问:为何humansMoney调用时未重置为100

理解闭包与作用域:为什么humansMoney不会重置?

首先我得把你提到的示例代码还原出来(闭包的经典例子基本都是这个路数),应该是类似这样:

function human() {
  // 外部函数的变量
  let humansMoney = 100;
  
  // 返回一个内部函数
  return function() {
    humansMoney--;
    console.log(humansMoney);
  };
}

// 这里调用了一次human(),得到它返回的内部函数,赋值给carl
const carl = human();

// 调用carl(),执行的是内部函数
carl(); // 输出99
carl(); // 输出98

你的困惑点在于:为什么每次调用carl()的时候,humansMoney不会重新变成100? 核心原因其实是:carl()根本没有调用human()——carl本身就是human()执行一次后返回的那个内部函数!

拆解整个过程:

  • 当你执行const carl = human();这一行时,human()函数被调用了一次:

    1. 创建了humansMoney变量并赋值为100;
    2. 返回了内部的匿名函数;
    3. 此时human()的执行上下文看似结束,但因为返回的内部函数引用了humansMoney,闭包会把这个变量所在的作用域“保留”下来,相当于给内部函数留了一把能访问这个变量的“钥匙”。
  • 之后每次调用carl(),都是直接执行那个被返回的内部函数:

    • 它不会重新触发human()的执行,所以humansMoney = 100这行代码不会再运行;
    • 它通过闭包访问的是之前human()执行时创建的那个humansMoney变量,所以每次调用只会让同一个变量递减。

举个生活化的例子:

把human()想象成一个制作存钱罐的机器:

  1. 你按下机器按钮(调用human()),机器做了一个装有100块钱的存钱罐,还给你一把能打开这个存钱罐的钥匙(返回内部函数);
  2. 这把钥匙就是carl,你每次用钥匙开门(调用carl()),都是从同一个存钱罐里拿钱,而不是让机器重新做一个新的存钱罐;
  3. 如果想要一个新的、初始100块的存钱罐,你得再按一次机器按钮(再调用一次human()),比如const alice = human();,这时候alice对应的就是另一个独立的存钱罐了。

验证你的假设:

如果真的想让每次调用都重置为100,那你需要每次都调用human(),比如:

// 每次都重新调用human(),得到新的内部函数,自然humansMoney会重置
human()(); // 99
human()(); // 99

这样每次执行human()都会创建一个新的humansMoney变量,所以每次的结果都是99,而不是递减。

内容的提问来源于stack exchange,提问作者josh_c

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:19:49