JS解构赋值问题记录

38 阅读2分钟

在做leetcode41.缺失的第一个正数

使用到了[nums[i], nums[nums[i] - 1]] = [nums[nums[i] - 1], nums[i]];

本意是交换两处下标的值,却发现执行一直死循环,调试了一下发现问题出现交换这里。

考虑数组[3, 4, -1, 1],在执行到i=0时,想要交换nums[0]nums[2],本意是要将数组变为[-1,4,3,1]

结果交换后数组变为了:

image.png

很明显越界了,我将[nums[i], nums[nums[i] - 1]] = [nums[nums[i] - 1], nums[i]]换为 const temp = nums[i]; nums[i] = nums[temp - 1]; nums[temp - 1] = temp;后,代码正常工作了

平常都是将[a,b] = [b,a]当做const temp = a;a = b;b = temp;的语法糖使用,以为两者时等价的,却在这里出了问题。

那么就开始研究一下解构赋值:

在 JavaScript 中,​​解构赋值的右侧表达式会先求值,但左侧的赋值是“从左到右”进行的​​。
对于 [nums[i], nums[nums[i] - 1]] = [nums[nums[i] - 1], nums[i]],实际执行顺序如下:

  1. 先计算右侧的 [nums[nums[i] - 1], nums[i]]

    • 先计算 nums[nums[i] - 1](记作 value1)。
    • 再计算 nums[i](记作 value2)。
    • 此时右侧为 [value1, value2]
  2. 然后对左侧赋值:

    • ​先赋值 nums[i] = value1​(这会直接修改 nums[i])。
    • ​再赋值 nums[nums[i] - 1] = value2​,但此时 nums[i] 已经被修改,导致 nums[i] - 1 可能不再是原来的索引!

​上面的示例为什么出错​

nums = [3, 4, -1, 1]i = 0nums[0] = 3):

  1. 右侧计算:

    • nums[nums[0] - 1] = nums[3 - 1] = nums[2] = -1
    • nums[0] = 3
    • 右侧为 [-1, 3]
  2. 左侧赋值:

    • 先执行 nums[0] = -1,此时 nums 变为 [-1, 4, -1, 1]
    • 再执行 nums[nums[0] - 1] = 3,即 nums[-1 - 1] = nums[-2] = 3(越界访问!)。

​问题出现​​:nums[i] 被修改后,nums[i] - 1 可能变成一个无效索引(如 -2),导致后续赋值出错或死循环。