关于 js 闭包(stale closure)问题的疑惑?

发布于 2022-09-11 23:58:25 字数 1329 浏览 24 评论 0

网上看到如下两段代码:

function createIncrement(i) {
  let value = 0;
  function increment() {
    value += i;
    console.log(value);
    const message = `Current value is ${value}`;
    return function logValue() {
      console.log(message);
    };
  }
  
  return increment;
}

const inc = createIncrement(1);
const log = inc(); // 1
inc();             // 2
inc();             // 3
// Does not work!
log();             // "Current value is 1"
function createIncrementFixed(i) {
  let value = 0;
  function increment() {
    value += i;
    console.log(value);
    return function logValue() {
      const message = `Current value is ${value}`;
      console.log(message);
    };
  }
  
  return increment;
}

const inc = createIncrementFixed(1);
const log = inc(); // 1
inc();             // 2
inc();             // 3
// Works!
log();             // "Current value is 3"

第二段代码与第一段代码的唯一区别仅仅在于, 将message变量移入了 logValue()函数中, 似乎就能"正确"读取到value的值

两端代码均存在嵌套的闭包, 我个人分析的时候比较困惑, 个人理解为: value由于inc()的调用应该是不断变化的, 而由于存在最顶端的createIncrement()/createIncrementFixed()这个函数造成的闭包, 所读取的 value 值应该总是最新的即为 3? 但是似乎和实际结果有些不太符合, 不知道哪里理解错了, 恳请知道的前辈能详细分析一下? 不胜感激!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦途 2022-09-18 23:58:25

从下面几个部分分析:

第一个误区:

  1. value 这个的变量的声明 被执行了几次? 只有一次对吧
  2. message 这个变量的声明,被执行了几次? 是不是 inc() 函数被执行几次就会声明几次

因此value 只被声明了一次,而且是在 局部作用域(闭包中),所以后续的访问都是同一个地方

message虽然也在局部作用域中,但是每次都被重新声明(而不是重新赋值);所以语法上看是 logValue 里面的 使用的是同一个,但是其实内存中不是同一个;因此 第一种写法,log 执行但结果都是当时 inc()执行时的值

第二个误区:

在第二种写法中不仅仅是代码的位置发生了变化,同时值的引用也发生了变化; 当你任何时候执行 log 时,他都是访问 value 的值而和 message 没关系了,然而我们之前说了 value 会不断被重新赋值,因此 log 每次执行都是拿到最新的。

第三 换个写法实现,让message 也只声明一次,代码如下

function createIncrement(i) {
  let message;
  let value = 0;
  function increment() {
    value += i;
    console.log(value);
    message = `Current value is ${value}`;
    return function logValue() {
      console.log(message);
    };
  }
  return increment;
}

这个时候 任何时候执行 log 也是一样 拿到最新的值

希望对你有帮助

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文