变量连续赋值与分别赋值的区别

Table of Contents

平时工作里都是每个变量单独声明赋值的,今天刷 leetcode 的时候用了连续赋值,然后就踩坑了。

问题

题目是:109. 有序链表转换二叉搜索树

解法:

/**
快慢指针找中点
 */
var sortedListToBST = function(head) {
  if (!head) return head
  if (!head.next) {
    head.left = null
    head.right = null
    return head
  }
  // let fast = slow = head
  let fast = head
  let slow = head
  let pre = null
  // 找中点
  while(fast && fast.next) {
    pre = slow
    slow = slow.next
    fast = fast.next.next
  }
  // 断开左侧
  if (pre) pre.next = null
  slow.left = sortedListToBST(head)
  slow.right = sortedListToBST(slow.next)
  return slow
}

声明赋值变量 fast 和 slow 的时候,第一次用的连续赋值,这导致解答错误。

[-10,-3,0,5,9] => [-3, -10]

换成分别声明赋值后才正确。

[-10,-3,0,5,9] => [0,-3,9,-10,null,5]

探索

连续声明赋值语句:let fast = slow = head 等于 let fast = (slow = head)。在函数 while 循环里开始和结束的位置打印出相关变量后发现,第一轮是没有问题的,问题在进入递归以后。

猜测进入递归以后的 slow 使用的是上一轮声明的 slow。

测验:

function test(end) {
  let a = b = { a: 1 }
  console.log(JSON.stringify(b))
  if (end) {
    b = 1
    return
  } else {
    test(true)
  }
  console.log(JSON.stringify(b))
}

test()
// {"a":1}
// {"a":1}
// 1

第二轮的 b 影响了第一轮里的 b,这说明猜测是对的。连续声明赋值时,引擎从右往左执行,遇到已经存在的变量会直接使用。