The page as a tree
The browser reads todo.html and builds the DOM: a tree of objects called nodes. document is the root. Below it sit html, body and the ul, whose child is an li holding the text Milk.
Finding and making nodes
querySelector("#list") searches the tree from the top, node by node, for the first element whose id is list. It returns that ul object. list now refers to it: not a copy, the very node in the tree.
document.createElement("li") makes a brand-new, empty li element. It exists, but it is not in the tree yet, so it has no parent and cannot appear on the page. item refers to it.
Setting textContent puts the text Eggs inside the new li. The element changes, but it is still outside the tree, so nothing on the page knows about it.
Changing the tree
list.append(item) adds the li as the last child of the ul. The tree grows: the ul now has two children, Milk and then Eggs.
classList.add("new") adds the class new to the li. Now the style rule .new on line 1 of todo.html matches it, so the browser will draw it in bold.
list.firstElementChild is the first child of the ul that is an element: the Milk li. remove() takes it out of the tree. The ul has one child left, Eggs.
Reading it back
list.children is the ul's child elements. It is live: it always matches the tree as it is now. Its length is 1, so console.log prints 1.
The browser does not redraw the screen while a script is running. Once the script finishes, it draws the page from the tree as it is now: one bullet, Eggs, in bold. Milk is gone.
What happens
// step 1/9 · tree todo.html <ul id="list"><li>Milk</li></ul> browser builds one object (node) per element tree document → html → body → ul → li "Milk" parent ul is the parent of li; li is its child JavaScript reads and changes this tree
The figure shows only element nodes. The real tree also has a head element (the style element is placed in it), the script element, and text nodes: the text Milk is itself a text node inside the li, and the line breaks between the tags become text nodes too. list and item hold references to node objects, not copies. Changing an element through a variable changes the one node in the tree.