为什么 this.tail 在我的链表 class 中更改了 this.head 的 属性?
Why does this.tail change the property of this.head in my Linkedlist class?
考虑一个 LinkedList class,它模仿如下的 Linkedlist 数据结构:
class LinkedList {
constructor(value) {
this.head = {
value: value,
next: null
};
this.tail = this.head;
this.length = 1;
}
append(value) {
const newNode = {
value: value,
next: null
}
this.tail.next = newNode; // why does this change head.next ?
this.tail = newNode;
this.length++;
return this;
}
}
let myLinkedList = new LinkedList(10);
myLinkedList.append(5);
日志输出
LinkedList {
head: { value: 10, next: { value: 5, next: null } },
tail: { value: 5, next: null },
length: 2
}
我看到 this.tail.next
也会更改 tail 的下一个 属性 (然后 this.tail = newNode
会将 tail 重新分配给 newNode)。我在这里不明白的是为什么 this.tail.next
也会更改 this.head 的下一个 属性?
此外,当将另一个数字附加到列表 myLinkedList.append(16)
时,它会不断更新 head 的下一个 属性,如下所示:
LinkedList {
head: { value: 10, next: { value: 5, next: [Object] } },
tail: { value: 16, next: null },
length: 3
}
也许一个可能的原因与我定义 this.tail = this.head
的构造函数有关?但我不太确定,因为这个只分配头到尾的值。
综上所述,我的问题是为什么this.tail.next = newNode
会改变下一个属性的头部?另外,附加另一个值时,为什么它会更改 head.next.next 等等?
当构造函数有 运行、this.tail
和 this.head
引用同一个对象时,因此您对 this.tail.next
所做的任何赋值在 this.head
中都是可见的,因为那确实是对正在变异的同一对象的引用。
想象一下可能会有所帮助。一旦构造函数有了运行,我们就有了这种情况:
this.head
↓
┌───────────┐
│ value: 10 │
│ next: null│
└───────────┘
↑
this.tail
那么append(5)
会先创建一个新的节点:
this.head newNode
↓ ↓
┌───────────┐ ┌───────────┐
│ value: 10 │ │ value: 5 │
│ next:null │ │ next:null │
└───────────┘ └───────────┘
↑
this.tail
然后执行this.tail.next = newNode;
,这是对第一个对象中那个next
属性的修改:
this.head newNode
↓ ↓
┌───────────┐ ┌───────────┐
│ value: 10 │ │ value: 5 │
│ next: ———————→ │ next:null │
└───────────┘ └───────────┘
↑
this.tail
确实,这也改变了 this.head.next
... 因为它完全一样 属性。
然后执行this.tail = newNode;
:
this.head newNode
↓ ↓
┌───────────┐ ┌───────────┐
│ value: 10 │ │ value: 5 │
│ next: ———————→ │ next:null │
└───────────┘ └───────────┘
↑
this.tail
下一次调用append
时,second对象的next
属性会被更新,所以我们得到:
this.head newNode
↓ ↓
┌───────────┐ ┌───────────┐ ┌───────────┐
│ value: 10 │ │ value: 5 │ │ value: 16 │
│ next: ———————→ │ next: ———————→ │ next:null │
└───────────┘ └───────────┘ └───────────┘
↑
this.tail
是的,这个变化也可以从 this.head
追踪到,因为...它是一个链表...所以它 应该 是可追踪的。由于每个 next
属性 都指向下一个节点,因此您可以找到从 head
到任何节点的路径。
考虑一个 LinkedList class,它模仿如下的 Linkedlist 数据结构:
class LinkedList {
constructor(value) {
this.head = {
value: value,
next: null
};
this.tail = this.head;
this.length = 1;
}
append(value) {
const newNode = {
value: value,
next: null
}
this.tail.next = newNode; // why does this change head.next ?
this.tail = newNode;
this.length++;
return this;
}
}
let myLinkedList = new LinkedList(10);
myLinkedList.append(5);
日志输出
LinkedList {
head: { value: 10, next: { value: 5, next: null } },
tail: { value: 5, next: null },
length: 2
}
我看到 this.tail.next
也会更改 tail 的下一个 属性 (然后 this.tail = newNode
会将 tail 重新分配给 newNode)。我在这里不明白的是为什么 this.tail.next
也会更改 this.head 的下一个 属性?
此外,当将另一个数字附加到列表 myLinkedList.append(16)
时,它会不断更新 head 的下一个 属性,如下所示:
LinkedList {
head: { value: 10, next: { value: 5, next: [Object] } },
tail: { value: 16, next: null },
length: 3
}
也许一个可能的原因与我定义 this.tail = this.head
的构造函数有关?但我不太确定,因为这个只分配头到尾的值。
综上所述,我的问题是为什么this.tail.next = newNode
会改变下一个属性的头部?另外,附加另一个值时,为什么它会更改 head.next.next 等等?
当构造函数有 运行、this.tail
和 this.head
引用同一个对象时,因此您对 this.tail.next
所做的任何赋值在 this.head
中都是可见的,因为那确实是对正在变异的同一对象的引用。
想象一下可能会有所帮助。一旦构造函数有了运行,我们就有了这种情况:
this.head
↓
┌───────────┐
│ value: 10 │
│ next: null│
└───────────┘
↑
this.tail
那么append(5)
会先创建一个新的节点:
this.head newNode
↓ ↓
┌───────────┐ ┌───────────┐
│ value: 10 │ │ value: 5 │
│ next:null │ │ next:null │
└───────────┘ └───────────┘
↑
this.tail
然后执行this.tail.next = newNode;
,这是对第一个对象中那个next
属性的修改:
this.head newNode
↓ ↓
┌───────────┐ ┌───────────┐
│ value: 10 │ │ value: 5 │
│ next: ———————→ │ next:null │
└───────────┘ └───────────┘
↑
this.tail
确实,这也改变了 this.head.next
... 因为它完全一样 属性。
然后执行this.tail = newNode;
:
this.head newNode
↓ ↓
┌───────────┐ ┌───────────┐
│ value: 10 │ │ value: 5 │
│ next: ———————→ │ next:null │
└───────────┘ └───────────┘
↑
this.tail
下一次调用append
时,second对象的next
属性会被更新,所以我们得到:
this.head newNode
↓ ↓
┌───────────┐ ┌───────────┐ ┌───────────┐
│ value: 10 │ │ value: 5 │ │ value: 16 │
│ next: ———————→ │ next: ———————→ │ next:null │
└───────────┘ └───────────┘ └───────────┘
↑
this.tail
是的,这个变化也可以从 this.head
追踪到,因为...它是一个链表...所以它 应该 是可追踪的。由于每个 next
属性 都指向下一个节点,因此您可以找到从 head
到任何节点的路径。