Incidents manipulation of the page and asynchronous data fetching
HTML and CSS describe how the page looks when it loads. JavaScript is what makes it react afterwards: open a menu on click, validate a form, fetch new data and update content without reloading the entire page. The key to it all is the DOM.
When the browser loads HTML it builds a model of the page in memory called the DOM (Document Object Model). It is a tree of elements which JavaScript can read and modify. Change something in the DOM and the browser updates what the user sees – that's how a page comes alive after loading. You find elements in the tree read or change their content and properties and add or remove elements.
Most interaction is based on events: a click a key press a form being submitted a page finishing loading. You listen for an event on an element and attach a function to it that runs when the event happens. That's how you tie user actions together with code that does something. Keep these functions small and let them call other functions so the code becomes readable.
Something takes time – especially fetching data over the network. It must not freeze the entire page while waiting. Therefore JavaScript is asynchronous: you ask for the data and get a message when the answer arrives while the rest of the page keeps working. When the answer comes – typically as JSON from an API – you update the DOM with the new content. It's the technique that lets a page fetch more without reloading.
Do not put JavaScript code directly into HTML elements. Keep the code together in its own files and tie the behaviour to the page from there. This keeps the three areas of responsibility — structure, appearance and behaviour — separate, just like with CSS, and makes the page much easier to read and maintain.
“JavaScript without DOM is just a calculation. It's the meeting with the page that makes the language web.”
— Common teaching principle in front-end development