The values held by variables are of basic types like strings and numbers which are different but can often be used interchangeably so long as you are smart enough to know when they can't.
Some values are objects like arrays and functions. These are so flexible that you can put functions into objects and pass them around like one thing. You can even put functions into functions which has proven to be useful in at least one case.
Additional types can be described within the language initially by manipulating prototypes and now civilized by class definitions.
Variables holding values come and go at various times following rules that are hard to remember. Many tricks are possible but one should test anything that they haven't already see work as expected sometime today.
More versatile declarations using let and const along with stricter rules about undeclared variables has brought some order to coding practice.
Statements are evaluated one after another without interruptions except in cases that are well identified. Loading a file or encountering a script tag get this going. Function definitions are made to appear as if they already happened but other things must be carefully ordered.
There is a knack to registering for and handling events. Of course there are multiple choices and much lore as to which is better.
The recent introduction of async functions and the await operation within them reasonably approximates linear flow within code that is managing non-linear activities.
A small script can interact directly with the document and window that surrounds it as well as speaking to the internet if it knows its way around.
Huge libraries have emerged that aim to simplify some i/o aspect by 2x while they complicate other issues by 10x. These are best ignored except by enterprise.