Because the entire code block is effectively one big main
. In JavaScript, global code can have all of the constructs function code can have, and has stepwise execution, just like functions do. In fact, when the JS engine processes the code block as a whole, it does very nearly the same things that it does when processing a function call. See the specification's sections 10.4.1 ("Entering Global Code") and 10.4.3 ("Entering Function Code") and note how similar they are.
C doesn't allow stepwise code at the global level (you can have all sorts of initializers, and they can get kind of stepwise, but that's a different topic). And so C needs an explicit entry point (main
). In JavaScript, the entry point is the beginning of the code.
Regarding your question below about whether global code is sequential. The answer is yes, it's exactly like code in a function that way. So:
var x, y, z;
x = 1;
y = 2;
z = x + y;
alert("z is " + z);
...will alert "z is 3"
. The code runs sequentially, top to bottom.
There are a couple of things that happen before the stepwise code is executed, though, which is useful to know. The most significant is that any declarations in the source text of the scope being entered are processed before the stepwise code begins. JavaScript has two main types of declarations: Variable declarations, and function declarations:
The name of any variable declared with var
is added to the scope (with the value undefined
) before any stepwise code is executed. (More: Poor, misunderstood var
)
Function declarations are processed and the function names added to the scope before any stepwise code is executed. (JavaScript also has something else, called a function expression, which is stepwise code. More on that below.)
So for instance, in this source text:
var x;
x = 1;
foo();
function foo() {
}
the declarations are
var x;
function foo() {
}
and the stepwise code is
x = 1;
foo();
The declarations are processed first. This is why the call to foo
works. (These same rules apply to the source text within functions.) This processing of declarations before anything else is sometimes called "hoisting," because the declarations are in a sense lifted from their location in the source text and moved to the very beginning. I prefer to think of it as two passes through the source: The first pass does declarations, the second executes stepwise code.
(Side note: Declaring a variable more than once in the same scope is perfectly legal [though pointless]. Declaring two functions with the same name is also legal; the latter declaration overrides the earlier one.)
(Side note 2: ES2015 [ES6] introduced let
and const
variable declarations, which behave somewhat differently from var
. You can't declare a variable twice with them, they have block scope, and you can't use the variable prior to the statement where it's declared. So they're mostly not hoisted [there is something slightly like hoisting in that they prevent access to a shadowed variable in a containing scope even before the let x
or whatever line].)
More detail, and possibly getting a bit technical:
var
If var
happens before the stepwise code is run, you may be wondering about this:
var x = 1;
Does that happen before stepwise code, or as part of it? The answer is that in reality, that's just shorthand for two very different things:
var x;
x = 1;
The var x;
part happens before the stepwise code, the x = 1;
part is stepwise code and is executed when we reach it in the sequence. So:
alert(x); // "undefined" -- there **is** a variable `x`; it has the value `undefined`
var x = 1;
alert(x); // "1" -- now `x` has the value `1`
Function declarations
JavaScript has two different, but very similar-looking, things: Function declarations, and function expressions. You can tell which is which by whether you're using the resulting function as part of the expression in which it's defined.
Here's a function declaration:
function foo() {
}
These are all function expressions (we use the resulting function value as part of the expression; in computer science terminology, the function is used as a right-hand value):
// 1: Assigning the result to something
var x = function() {
};
// 2: Passing the result into a function
bar(function() {
});
// 3: Calling the function immediately
(function(){
})();
// 4: Also calling the function immediately (parens at end are different)
(function(){
}());
// 5: Also calling the function immediately
!function(){
}();
// 6: Syntax error, the parser needs *something* (parens, an operator like ! or
// + or -, whatever) to know that the `function` keyword is starting an *expression*,
// because otherwise it starts a *declaration* and the parens at the end don't make
// any sense (and function declarations are required to have names).
function(){
}();
The rule is that function declarations are processed before the stepwise code begins. Function expressions, like all other expressions, are processed where they're encountered.
One final side note: This is a named function expression:
var f = function foo() {
};
We use it as a right-hand value, so we know it's an expression; but it has a name like function declarations do. This is perfectly valid and legal JavaScript, and what it's meant to do is create a function with a proper name (foo
) as part of the stepwise code. The name of the function is not added to the scope (as it would be if it were a function declaration).
However, you won't see named function expressions in very many places, because JScript (Microsoft's JavaScript engine) gets them horribly and utterly wrong, creating two separate functions at two different times.