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

JavaScript模块模式变量存储疑问:timesRun外部获取值始终为0

问题:模块模式下外部无法获取更新后的变量值

先看这段JavaScript模块模式代码:

const Formatter = (function() {
  let timesRun = 0;
  
  const log = (message) => console.log(`[${Date.now()}] Logger: ${message}`);
  const setTimesRun = () => {
    log("Setting times run");
    ++timesRun;
    console.log(timesRun);
  }

  const makeUppercase = (text) => {
    log("Making uppercase");
    setTimesRun();
    return text.toUpperCase();
  };

  return {
    makeUppercase,
    timesRun,
  }
})()

console.log(Formatter.makeUppercase("tomek"));
console.log(Formatter.timesRun);

console.log(Formatter.makeUppercase("foo"));
console.log(Formatter.timesRun);

console.log(Formatter.makeUppercase("hey"));
console.log(Formatter.timesRun);

调用Formatter.makeUppercase()时,内部的timesRun能正常递增,控制台打印的内部值是对的,但外部通过Formatter.timesRun获取到的始终是0,搞不懂为什么内部和外部的数值不一样,也不清楚这个变量到底存在哪里。


原因与解决办法

问题根源

你在返回的对象里直接写timesRun,本质是把当时的timesRun值(也就是0)复制了一份放到返回的对象里——因为timesRun是基本类型(数字),赋值是值传递,和闭包里的timesRun不是同一个引用。

闭包里的timesRun存在于立即执行函数(IIFE)的私有作用域中,外部无法直接访问;而返回对象里的timesRun只是初始值的一个静态副本,后续闭包里的timesRun更新时,这个副本不会同步变化。

解决办法

方法1:新增getter函数

在返回的对象里定义一个获取最新值的函数,每次调用都去闭包里拿当前的timesRun:

const Formatter = (function() {
  let timesRun = 0;
  
  const log = (message) => console.log(`[${Date.now()}] Logger: ${message}`);
  const setTimesRun = () => {
    log("Setting times run");
    ++timesRun;
    console.log(timesRun);
  }

  const makeUppercase = (text) => {
    log("Making uppercase");
    setTimesRun();
    return text.toUpperCase();
  };

  return {
    makeUppercase,
    getTimesRun: () => timesRun,
  }
})()

console.log(Formatter.makeUppercase("tomek"));
console.log(Formatter.getTimesRun()); // 调用方法获取最新值

console.log(Formatter.makeUppercase("foo"));
console.log(Formatter.getTimesRun());

console.log(Formatter.makeUppercase("hey"));
console.log(Formatter.getTimesRun());

方法2:用ES6 getter语法

让返回对象的timesRun成为一个动态访问器属性,每次访问时自动获取闭包里的最新值:

const Formatter = (function() {
  let timesRun = 0;
  
  const log = (message) => console.log(`[${Date.now()}] Logger: ${message}`);
  const setTimesRun = () => {
    log("Setting times run");
    ++timesRun;
    console.log(timesRun);
  }

  const makeUppercase = (text) => {
    log("Making uppercase");
    setTimesRun();
    return text.toUpperCase();
  };

  return {
    makeUppercase,
    get timesRun() {
      return timesRun;
    }
  }
})()

console.log(Formatter.makeUppercase("tomek"));
console.log(Formatter.timesRun); // 直接访问即可获取最新值

console.log(Formatter.makeUppercase("foo"));
console.log(Formatter.timesRun);

console.log(Formatter.makeUppercase("hey"));
console.log(Formatter.timesRun);

两种方法的核心逻辑一致:每次外部需要获取值时,都去访问闭包里的原始变量,而不是依赖初始的静态副本。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 16:55:41