This questions applies to the JavaScript language broadly, but the specific context I encountered this issue with was while solving Linked List problems on LeetCode. In 206. Reverse LInked List, you can use Javascript's Destructuring Assignment feature to avoid using temp variables as you shuffle around pointers between current and previous, for example this is an accepted solution where destructuring assignment correctly changes the .next pointers in a singly linked object:
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
var reverseList = function(head) {
let [prev, curr] = [null, head]
while (curr != null) {
[curr.next, curr, prev] = [prev, curr.next, curr]
}
return prev
}
Then why does this solution work for 141. Linked List Cycle...
var hasCycle = function(head) {
if (!head) return false
let [slow, fast] = [head, head]
while (fast) {
if (!fast.next) return false
slow = slow.next
fast = fast.next.next
// [slow, fast] = [slow.next, fast.next.next]
if (slow == fast) return true
}
return false
};
but the almost identical solution, which attempts to use destructuring assignment to merely save space, fails to update the pointer value (causing false positives as the initial values pointing to head are never changed)? Also, the act of console logging before using destructuring assignment changes the behavior - instead of the false positive, now the code throws a runtime error for TypeError: Cannot set property '#<ListNode>' of undefined
var hasCycle = function(head) {
if (!head) return false
let [slow, fast] = [head, head]
while (fast) {
if (!fast.next) return false
// slow = slow.next
// fast = fast.next.next
console.log(slow.val, fast.val)
[slow, fast] = [slow.next, fast.next.next]
if (slow == fast) return true
}
return false
};
The only difference between the failed usage in 141 and the successful usage in 206 is using .next.next instead of simply .next, which leads me to believe that destructuring assignment is failing for a reason that is related to nested objects or pointers, but I can't find a solution on StackOverflow or by googling.
Why does the line before Javascript Destructuring Assignment fail to automatically insert a semicolon using ASI?
Automatic Semicolon Insertion (ASI) does not insert a semicolon on the end of a line of code when combining the following line would result in "valid" javascript code.
More specifically, common examples would be when the following line begins with either a ( or [, which javascript may interpret as a call to a function or index of an array, respectively.
Examples illustrating when a semicolon needs to be inserted include:
let a = 0
let b = a
(0 == false) ? findTruth() : contemplate()
// interpreted as
// let a = a(0 == false) ...
or, within the context of the example,
let a = 0
let b = 1
[a, b] = [b, a]
// interpreted as
// let b = 1[a, b] = [b, a]
I found that this reference was illustrative on the types of edge cases where ASI will not insert semicolons: https://flaviocopes.com/javascript-automatic-semicolon-insertion/