在这个陈旧的关闭中*实际上*发生了什么?

What is *actually* happening within this stale closure?

我觉得好像我对闭包的了解几乎在那里,但我正在努力理解为什么第一个代码片段记录 0(是陈旧的闭包),但是,第二个代码片段有效并记录更新值 ..

这是某种参考问题吗?

在第一个例子中,我们不是跟踪count的引用,只是将它的初始值赋给message吗?

通过将消息变量移动到日志函数中,我们是否以某种方式告诉 JS 跟踪计数值的引用?

function createIncrement() {
  let count = 0;

  function increment() {
    count++;
  }

  let message = count;
  function log() {
    console.log(message);
  }

  return [increment, log];
}

const [increment, log] = createIncrement();

increment();
log();

// this will log 0

function createIncrement() {
  let count = 0;

  function increment() {
    count++;
  }

  function log() {
    let message = count;
    console.log(message);
  }

  return [increment, log];
}

const [increment, log] = createIncrement();

increment();
log();

// this will log 1

In the first example, are we not tracking the reference of count and only assigning its initial value to message?
By moving the message variable inside of the log function are we somehow telling JS to track the reference of the count value?

这就是您正在努力解决的问题。让我们尝试分解那里发生的事情。

其核心是:

let count = 0;
let message = count;
console.log(message);
count++; // it's exactly the same as count = count + 1;
console.log(message); // still prints 0

这与闭包无关,而与数字是不可变值有关。当我们递增 count 时,我们为变量分配了一个值为 1 的数字的新实例。 message 仍然指向旧实例(值,在本例中是相同的),因此日志将打印相同的旧值。

如果我对你的误解没有理解错的话 (!) 你在想象 count 是一个容器,你可以在其中插入一个数值,这有点不对。

它是一个指向内存中某处的不可变数值的指针。当您执行 message = count 时,您确保 message 和 count 指向相同的内存地址,其中包含 0.

当你写 count++ 时,你在内存中的某处为数字 1 分配了一个新数字,并且 count 现在指向新对象。 message 不受此操作影响。 这是关键点,我认为crystal不清楚

在您的第二个示例中,message 会在您每次登录时重新分配,因此它将始终持有对正确值的引用。