为什么不在功能副本中分配变量而不是引用它

发布于 2025-02-03 14:28:59 字数 1876 浏览 2 评论 0原文

我有此代码:

function makeArmy() {
  let shooters = [];

  let i = 0;
  while (i < 10) {
    let shooter = function () {
      console.log(i);
      // that should show its number
    };
    shooters.push(shooter); // and add it to the array
    i++;
  }

  // ...and return the array of shooters
  return shooters;
}

let army = makeArmy();

// all shooters show 10 instead of their numbers 0, 1, 2, 3...
army[0](); // 10 from the shooter number 0
army[1](); // 10 from the shooter number 1
army[2](); // 10 ...and so on.

发生这种情况是因为i始终是对makearmy()函数内部i的引用。

如果我们将代码调整为:

function makeArmy() {
  let shooters = [];

  let i = 0;
  while (i < 10) {
    // copy the varible i into the while lexical scope
    let j = i
    let shooter = function () {
      console.log(j);
      // that should show its number
    };
    shooters.push(shooter); // and add it to the array
    i++;
  }

  // ...and return the array of shooters
  return shooters;
}

let army = makeArmy();


army[0](); // 0
army[1](); // 1
army[2](); // 2

上述代码按预期工作,因为而不是引用变量i shooter()我们将其复制到j ,因此可以在其自身范围内对射击器功能可用。

现在,我的问题是,为什么在函数本身内部复制i变量?即使我仍在有效地复制该变量?我在这里想念什么?

代码:

function makeArmy() {
  let shooters = [];

  let i = 0;
  while (i < 10) {
    let shooter = function () {
      let j = i;

      console.log(j);
      // that should show its number
    };
    shooters.push(shooter); // and add it to the array
    i++;
  }

  // ...and return the array of shooters
  return shooters;
}

let army = makeArmy();

// all shooters show 10 instead of their numbers 0, 1, 2, 3...
army[0](); // 10 from the shooter number 0
army[1](); // 10 from the shooter number 1
army[2](); // 10 ...and so on.

I have this code:

function makeArmy() {
  let shooters = [];

  let i = 0;
  while (i < 10) {
    let shooter = function () {
      console.log(i);
      // that should show its number
    };
    shooters.push(shooter); // and add it to the array
    i++;
  }

  // ...and return the array of shooters
  return shooters;
}

let army = makeArmy();

// all shooters show 10 instead of their numbers 0, 1, 2, 3...
army[0](); // 10 from the shooter number 0
army[1](); // 10 from the shooter number 1
army[2](); // 10 ...and so on.

This happens because i is always a reference to the outer i inside the makeArmy() function.

If we adjust the code to be:

function makeArmy() {
  let shooters = [];

  let i = 0;
  while (i < 10) {
    // copy the varible i into the while lexical scope
    let j = i
    let shooter = function () {
      console.log(j);
      // that should show its number
    };
    shooters.push(shooter); // and add it to the array
    i++;
  }

  // ...and return the array of shooters
  return shooters;
}

let army = makeArmy();


army[0](); // 0
army[1](); // 1
army[2](); // 2

The above code works as expected because instead of referencing the variable i inside shooter() we are copying it into j, thus making it available to the shooter function in its own scope.

Now, my question is, why doesn't copying the i variable inside the function itself work? even though I'm effectively still copying the variable? What am I missing here?

Code:

function makeArmy() {
  let shooters = [];

  let i = 0;
  while (i < 10) {
    let shooter = function () {
      let j = i;

      console.log(j);
      // that should show its number
    };
    shooters.push(shooter); // and add it to the array
    i++;
  }

  // ...and return the array of shooters
  return shooters;
}

let army = makeArmy();

// all shooters show 10 instead of their numbers 0, 1, 2, 3...
army[0](); // 10 from the shooter number 0
army[1](); // 10 from the shooter number 1
army[2](); // 10 ...and so on.

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

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

发布评论

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

评论(2

豆芽 2025-02-10 14:28:59

因为您正在复制i已经是10的时候。

实际上,使用让j = i Inner 函数中,直接使用i没有区别,因为该分配也仅执行当您调用该内部函数时,如前所述, i 已经是10,因为调用在循环完成后很长时间发生,在EG 陆军中[0]()

如您指出的那样,如果您将移动j = i在内部功能之外(但仍在循环内),则可以工作。这样,对本地变量j的评估立即发生在每个迭代上,并且内部功能随后涉及其正确值的10种不同的j以前是在i具有您想要的相应值的那个时间点设置的。


顺便说一句,如果您将循环使用使用 让让具有一些“魔术”,则此问题将不存在为每次迭代创建一个半分开的范围(此工作的确切方式是更复杂的)。

  for (let i = 0; i < 10; i++) {
    let shooter = function () {
      console.log(i);
    };
    shooters.push(shooter);
  }

Because you are copying at a time at which i is already 10.

In fact, with let j = i in the inner function, there will be no difference to using i directly, because that assignment also executes only when you invoke that inner function, and as said, at this point i will already be 10, since the invocation happens long after the loop completed, in e.g. army[0]().

As you noted, it works if you move the let j = i outside of the inner function (but still inside the loop). This way, the assigment to the local variable(s) j happens on each iteration immediately, and the inner function later refers to those 10 different j's with their right values that were previously set at that point in time when i had the respective value that you wanted.


By the way, this problem won't exist if you'd use a for loop instead because for with let has some "magic" that creates a semi-separated scope for each iteration (the exact way this works is a bit more complicated).

  for (let i = 0; i < 10; i++) {
    let shooter = function () {
      console.log(i);
    };
    shooters.push(shooter);
  }
趁微风不噪 2025-02-10 14:28:59

当您调用console.log(i)在您的射击器函数i的值中是指一个while循环结束的值,因此我将是最后一个值它有。在您的情况下,i的值会随着时间而变化,显示了它的最后一个值。当您将其分配给变量(令j = i)时,您会复制该值而不是参考,以便您为您提供所需的结果。

When you call console.log(i) in your shooter function i's value refers to the one that has once the while loop ended, thus i would be the last value it had. In your case i's value changes over time, showing the last value it had. When you assign that to a variable (let j = i) you copy that value and not the reference so it gives you the result you want.

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