How can this.tail.next update both this.tail and whatever this.tail.next is referencing, in the first case, this.head, and so forth?
this.head has a (deep) reference to this.tail via the next property chain. So when you mutate this.tail.next, then this change can be "seen" from any other node that has a next chain that eventually ends up at this.tail.
Especially when this.tail is overwritten to newNode right afterwards. Shouldn't that overwrite this.head entirely?
No, assigning to this.tail does not affect the object that this.tail was referencing before that assignment. The only way to alter that object is to change the value of one of its properties.
How is the next key "saved" despite the entire this.tail being set to newNode?
As said above, the object that this.tail referred to was not altered by this assignment. The assignment just "switches" this.tail to (reference) a different object.
Separately, I understand that this.tail.next is referencing the node before - but how does the reference's next key get updated if all we are doing is setting this.tail.next, and not its reference?
When we do this.tail.next = newNode we are setting a reference to what newNode refers to. At that moment the linked list has become one node longer. When we then follow up with this.tail = newNode we make sure that this.tail references the last node in the list, which is an invariant we want to restore.
It may help to visualise the example you have presented in your script.
When const linkedList = new LinkedList(5) is executed, we set this.head to a new node, and we get this state:
 linkedList (this)
  ↓
┌───────────┐    ┌───────────┐
│ head: ───────> │ value: 5  │
│           │    │ next: null│
└───────────┘    └───────────┘ 
The left box is the linked list instance, and the right box is the (first) Node instance.
The constructor continues with this.tail = this.head. This merely copies the reference to the new object into a new tail property:
 linkedList (this)
  ↓
┌───────────┐    ┌───────────┐
│ head: ───────> │ value: 5  │
│ tail: ───────> │ next: null│
└───────────┘    └───────────┘ 
I skip the length property management here, as it is not relevant to the question.
Then linkedList.append(2) is executed. First newNode gets a reference to a new node which is for the moment is not related to the list in any way:
 linkedList (this)
  ↓
┌───────────┐    ┌───────────┐    ┌───────────┐
│ head: ───────> │ value: 5  │    │ value: 2  │
│ tail: ───────> │ next: null│    │ next: null│
└───────────┘    └───────────┘    └───────────┘
                                    ↑
                                   newNode
...and this reference is assigned to this.tail.next as well:
 linkedList (this)
  ↓
┌───────────┐    ┌───────────┐    ┌───────────┐
│ head: ───────> │ value: 5  │    │ value: 2  │
│ tail: ───────> │ next: ───────> │ next: null│
└───────────┘    └───────────┘    └───────────┘
                                    ↑
                                   newNode
So the effect of this.tail.next = newNode is reflected by middle horizontal arrow. Note that indeed newNode and this.tail.next (if you follow the arrows) refer to the same node.
Now we execute this.tail = newNode. This is the (simple) effect of that:
 linkedList (this)
  ↓
┌───────────┐    ┌───────────┐    ┌───────────┐
│ head: ───────> │ value: 5  │    │ value: 2  │
│ tail: ──────┐  │ next: ───────> │ next: null│
└───────────┘ │  └───────────┘ ┌> └───────────┘
              └────────────────┘    ↑
                                   newNode
Note that with such an assignment mutates the linked list instance, but not any node instance. The append method finishes, and the newNode variable gets out of scope and is no longer relevant.
Let's continue with linkedList.append(8). Again a newNode variable gets a reference to a new node:
 linkedList (this)
  ↓
┌───────────┐    ┌───────────┐    ┌───────────┐    ┌───────────┐
│ head: ───────> │ value: 5  │    │ value: 2  │    │ value: 8  │
│ tail: ──────┐  │ next: ───────> │ next: null│    │ next: null│
└───────────┘ │  └───────────┘ ┌> └───────────┘    └───────────┘
              └────────────────┘                     ↑
                                                    newNode
...and again we mutate the node that tail is referring to with this.tail.next = newNode:
 linkedList (this)
  ↓
┌───────────┐    ┌───────────┐    ┌───────────┐    ┌───────────┐
│ head: ───────> │ value: 5  │    │ value: 2  │    │ value: 8  │
│ tail: ──────┐  │ next: ───────> │ next: ───────> │ next: null│
└───────────┘ │  └───────────┘ ┌> └───────────┘    └───────────┘
              └────────────────┘                     ↑
                                                    newNode
...and the only thing that remains is to let tail reference the last node (the invariant) with this.tail.next = newNode:
 linkedList (this)
  ↓
┌───────────┐    ┌───────────┐    ┌───────────┐    ┌───────────┐
│ head: ───────> │ value: 5  │    │ value: 2  │    │ value: 8  │
│ tail: ──────┐  │ next: ───────> │ next: ───────> │ next: null│
└───────────┘ │  └───────────┘    └───────────┘ ┌> └───────────┘
              └─────────────────────────────────┘    ↑
                                                    newNode
Hope this clarifies it.