为什么这个链表添加方法有效?

why is this linked-list add method working?

我创建了这个方法来将一个数字添加到链表中,但我不太明白它为什么有效。

如果你看一下下面的代码,你会注意到我创建了一个名为“current”的变量,它设置了 this.head 的内容,直到那时一切正常,但我不明白为什么 this.head 正在更新当前变量的值,如果我没有告诉 Javascript 这样做的话。

这是我的代码,非常感谢你们能给我的帮助

class Node {
  constructor(value, next_node = null) {
    this.value = value;
    this.next_node = next_node;
  }
}

class LinkedList {
  // setup head and tail
  constructor() {
    this.head = null;
    this.length = 0;
  }
  
  add(number) {
    let node = new Node(number)
    if(this.head === null){
      this.head = node;
    } else {
     let current = this.head;
     while(current.next_node !== null){
       current = current.next_node   
     }
      current.next_node = node;
      console.log(this.head)
    }
    this.length++
  }
  
  get(index) {
  }
}

const ll = new LinkedList();
ll.add(2)
ll.add(3)
ll.add(5)

可视化过程可能会有所帮助:

使用 const ll = new LinkedList() 创建列表后,我们可以将情况表示为:

 ll
  ↓
┌────────────┐  
│ head: null │
│ length: 0  │
└────────────┘

现在我们执行ll.add(2),它使this等同于ll,然后我们执行let node = new Node(number)。可以描述为:

 ll/this           node
  ↓                 ↓
┌────────────┐    ┌─────────────────┐
│ head: null │    │ value: 2        │
│ length: 0  │    │ next_node: null │
└────────────┘    └─────────────────┘

if条件为真,所以执行this.head = node,最后this.length++。对 add 的调用结束,因此 node 变量超出范围:

 ll/this
  ↓
┌────────────┐    ┌─────────────────┐
│ head: ──────── │ value: 2        │
│ length: 1  │    │ next_node: null │
└────────────┘    └─────────────────┘

ll.add(3)被执行时,我们就进入了你问题的核心。再次执行 let node = new Node(number)

 ll/this                                  node
  ↓                                        ↓
┌────────────┐    ┌─────────────────┐    ┌─────────────────┐
│ head: ──────── │ value: 2        │    │ value: 3        │
│ length: 1  │    │ next_node: null │    │ next_node: null │
└────────────┘    └─────────────────┘    └─────────────────┘

这次if条件为假,我们执行let current = this.head:

 ll/this                                  node
  ↓                                        ↓
┌────────────┐    ┌─────────────────┐    ┌─────────────────┐
│ head: ──────── │ value: 2        │    │ value: 3        │
│ length: 1  │    │ next_node: null │    │ next_node: null │
└────────────┘    └─────────────────┘    └─────────────────┘
                    ↑
                   current

由于while条件为假,循环不迭代,我们执行current.next_node = nodethis.length++:

 ll/this                                  node
  ↓                                        ↓
┌────────────┐    ┌─────────────────┐    ┌─────────────────┐
│ head: ──────── │ value: 2        │    │ value: 3        │
│ length: 2  │    │ next_node: ──────── │ next_node: null │
└────────────┘    └─────────────────┘    └─────────────────┘
                    ↑
                   current

这很关键:因为 current 引用与 this.head 相同的节点,无论您通过 this.head 还是通过 [=36= 查看节点的变化都是可见的]: 是同一个节点。

这个应该说清楚了。为了完成示例脚本,让我们也执行 ll.add(5)。在 else 块中 while 循环的开始处,我们有:

 ll/this                                                         node
  ↓                                                               ↓
┌────────────┐    ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│ head: ──────── │ value: 2        │    │ value: 3        │    │ value: 5        │
│ length: 2  │    │ next_node: ──────── │ next_node: null │    │ next_node: null │
└────────────┘    └─────────────────┘    └─────────────────┘    └─────────────────┘
                    ↑
                   current

现在循环进行一次迭代,使 current 指向第二个节点实例:

 ll/this                                                         node
  ↓                                                               ↓
┌────────────┐    ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│ head: ──────── │ value: 2        │    │ value: 3        │    │ value: 5        │
│ length: 2  │    │ next_node: ──────── │ next_node: null │    │ next_node: null │
└────────────┘    └─────────────────┘    └─────────────────┘    └─────────────────┘
                                           ↑
                                          current

最后,current.next_node = nodethis.length++被执行,之后变量nodecurrent结束它们的生命:

 ll
  ↓
┌────────────┐    ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│ head: ──────── │ value: 2        │    │ value: 3        │    │ value: 5        │
│ length: 3  │    │ next_node: ──────── │ next_node: ──────── │ next_node: null │
└────────────┘    └─────────────────┘    └─────────────────┘    └─────────────────┘

这完成了列表并间接改变了 ll.head 引用的内容。