In an online course, Kyle Simpson says the following code demonstrates the necessity of hoisting in javascript, because without hoisting "one of the functions would always be declared too late."
a(1) // 39
function a(foo){
if (foo > 20) return foo
return b(foo+2)
}
function b(foo){
return c(foo) + 1
}
function c(foo){
return a(foo*2)
}
But this works just fine.
var a = function(foo){
if (foo > 20) return foo
return b(foo+2)
}
var b = function(foo){
return c(foo) + 1
}
var c = function(foo){
return a(foo*2)
}
a(1) // 39
So what's the story? Convenience and placement of invocation aside, are there any situations that require hoisting?
The claim I've made about a non-hoisted JS being unable to support mutual recursion is just conjecture for illustration purposes. It's designed to help understand the need for the language to know about variables available in the scope(s). It's not a prescription for exact language behavior.
A language feature like hoisting -- actually hoisting doesn't exist, it's just a metaphor for variables being declared in scope environments ahead of time during compilation, before execution -- is such a fundamental characteristic that it can't easily be reasoned about when separated from the rest of the language's characteristics.
Morever, it is impossible to fully test this hypothesis in just JS. The snippet in the OP only deals with part of the equation, which is that it uses function expressions instead of function declarations to avoid function hoisting.
The language I was using to compare to for illustration is C, which for example requires function signatures to be declared in .h header files so that the compiler knows what a function looks like even if it hasn't "seen" it yet. Without it, the compiler chokes. That's a sort of manual hoisting in a sense. C does it for type checking, but one can imagine this sort of requirement existing for other reasons than that.
Another way of thinking about this is whether JS is a compiled language where everything has been discovered before it executes, or whether it is interpreted top-down in a single pass.
If JS were top-down interpreted, and it got to the definition of an a() function that referenced a b() inside it that it hadn't seen yet, that could be a problem. If that call expression was handled non-lazy, the engine couldn't figure out at that moment what the b() call would be about, because b() hadn't been processed yet. Some languages are lazy and some are non-lazy.
As is, JS is compiled first before execution, so the engine has discovered all the functions (aka "hoisting") before running any of them. JS also treats expressions as lazy, so together that explains why mutual recursion works fine.
But if JS had no hoisting and/or was not lazy, one can imagine the JS engine would be unable to handle mutual recursion because the circular reference between a() and b() would in fact mean that one of the two was always declared "too late".
That's really all I meant in the book.
Convenience and placement of invocation aside, there are not any situations that require hoisting.
Just make sure to declare all the functions before using them.
Note: In some browser, function a(){} creates a function with name a while var a = function(){} does not (considered anonymous function). The function name is used when debugging. You could also do var b = function a(){}.
The second block of code works fine because you are invoking a(1) after all the functions are initialized. Try the following block:
var a = function(foo){
if (foo > 20) return foo
return b(foo+2)
}
var b = function(foo){
return c(foo) + 1
}
a(1);
var c = function(foo){
return a(foo*2)
}
This will give an error Uncaught TypeError: c is not a function because function assigned to c is not hoisted. This is the reason why you need hoisting.
Because if you declare functions as in your first block of code, all the functions will be hoisted and you can invoke a anywhere in the code. This is not true in the other cases.
Related
I am new to JS and was learning the role of execution context in JS and asked myself what is the benefit of execution context in JS and why JS is run via execution context. The second question is as we know there are global and functional execution contexts and each context has two phases creation phase and execution phase. So, why we need these two phases? what is the point of having them.
The concept of an "execution context" provides a way of reasoning about what happens when the global environment is created and executed, or when a function is called. It's a conceptual container for the local variables (globals, in the case of the global environment), parameters (for functions), etc. A JavaScript engine can be written without literally having any object it calls an "execution context," as long as it implements the language in keeping with the spec's defined execution context behavior.
One thing that the execution context helps explain is the behavior of closures. A function created within a given execution context has (conceptually) a reference to that context, even after the function call related to the context has completed:
function foo(answer) {
return function say() {
console.log(answer);
};
}
const s = foo(42);
s(); // 42
That works because the function say has a reference to the context of the call to foo that created it (well, more specifically to the thing called its "lexical environment"). That lexical environment continues to exist after foo returns because something still has a reference to it (say). So the call to say afterward works.
The reason for having two phases is to allow use of identifiers before their declaration. This is primarily useful for function declarations:
main();
function main() {
console.log("Worked");
}
The first phase processes the function declarations (and var statements), and then the step-by-step phase runs the code. Without the first phase, the code above would fail as of main(); because main would be undeclared. Of course, with the simple example above, you could just move the main(); call to after the function declaration, but more complicated cases become harder to solve in that way. Languages that didn't have two phases (early C, for instance) had to provide a mechanism for "forward declaring" things that would be defined later. Having two phases means JavaScript doesn't have to have those. (To be fair, C also differs from JavaScript in that it needs to know what all identifiers refer to during compilation, even if the identifiers are in code within functions. So it needed forward declarations just to allow foo and bar to call one another. JavaScript doesn't check the identifiers used within functions until the function is called, so some of the reasons for forward declarations in C wouldn't come up in JavaScript even if it didn't have two phases.)
It wasn't perfectly successful. Having var statements initialize the variables they declare with undefined before the var statement is reached in the code was often the source of bugs and confusion:
console.log(answer); // undefined
var answer = 42;
It's easy for people to be confused by the fact that half of the var answer = 42; was done early (the var answer part), but the other half (answer = 42;) isn't done until later when that statement is reached.
That's why let and const create, but don't initialize, their variables during that first phase. You can use a variable above where it's declared, but only in code that runs after the initialization:
function foo() {
console.log(answer);
}
// foo(); <== Would fail, `answer` isn't initialized yet
let answer = 42;
foo(); // Works, logs 42
This question already has answers here:
Explain the encapsulated anonymous function syntax
(10 answers)
Closed 7 years ago.
I'm reading up on JavaScript IIFE and so far the understand concept, but I am wondering about the outside parenthesis. Specifically, why are they required? For example,
(function() {var msg='I love JavaScript'; console.log(msg);}());
works great, but
function() {var msg='I love JavaScript'; console.log(msg);}();
generates a syntax error. Why? There are lots of discussions on IIFE, but I'm not seeing a clear explanation about why the parentheses are required.
There are two ways to create functions in JavaScript (well, 3, but let's ignore new Function()). You can either write a function declaration or write a function expression.
A function declaration in itself is a statement and statements by themselves don't return values (let's also ignore how the debugging console or Node.js REPL print return values of statements). A function expression however is a proper expression and expressions in JavaScript returns values that can be immediately used.
Now, you may have seen people saying that the following is a function expression:
var x = function () {};
It may be tempting to conclude that the syntax:
function () {};
is what makes it an expression. But that's wrong. The syntax above is what makes it an anonymous function. And anonymous functions can either be a declaration or an expression. What makes it an expression is this syntax:
var x = ...
That is, everything to the right of an = sign is an expression. Expressions make it easier to write math formulas in programming languages. So in general everywhere that math is expected to be processed is an expression.
Some of the forms of expressions in JavaScript include:
everything to the right of an = operator
things in braces () that are not function call braces
everything to the right of a math operator (+,-,*,/)
all the arguments to the ternary operator .. ? .. : ..
When you write:
function () {}
it is a declaration and does not return a value (the declared function). Therefore trying to call the non-result is an error.
But when you write:
(function () {})
it is an expression and returns a value (the declared function) which may be used immediately (for example, may be called or may be assigned).
Note the rules for what counts as expressions above. From that it follows that braces are not the only things that you can use to construct an IIFE. Below are valid ways for constructing IIFEs (because we write function expressions):
tmp=function(){}()
+function(){}()
-function(){}()
0/function(){}()
0*function(){}()
0?0:function(){}()
(function(){}())
(function(){})()
You may actually see one of the above non-standard forms (particularly the + version) in third-party libraries, because they want to save one byte. But I strongly advise you to only use the brace forms (either are fine), because they are widely recognized as IIFEs by other programmers.
The version of IIFE that is wrapped in parenthesis works, because this marks the declaration of the internal function declaration as an expression.
http://benalman.com/news/2010/11/immediately-invoked-function-expression/
For more detailed explanation please see:
Advanced JavaScript: Why is this function wrapped in parentheses?
HINT:
The invocation operator (()) only works with expressions, not declarations.
This will be a long-winded answer, but will give you the necessary background. In JavaScript there are two ways functions can be defined:
A function definition (the classical kind)
function foo() {
//why do we always use
}
and then the more obscure type, a function expression
var bar = function() {
//foo and bar
};
In essence the same thing is going on at execution. A function object is created, memory is allocated, and an identifier is bound to the function. The difference is in the syntax. The former is itself a statement which declares a new function, the latter is an expression.
The function expression gives us the ability to insert a function any place where a normal expression would be expected. This lends its way to anonymous functions and callbacks. Take for instance
setTimeout(500, function() {
//for examples
});
Here, the anonymous function will execute whenever setTimeout says so. If we want to execute a function expression immediately, however, we need to ensure the syntax is recognizable as an expression, otherwise we have ambiguity as to whether of not we mean a function expression or statement.
var fourteen = function sumOfSquares() {
var value = 0;
for (var i = 0; i < 4; i++)
value += i * i;
return value;
}();
Here sumOfSquares is immediately invoked because it can be recognized as an expression. fourteen becomes 14 and sumOfSquares is garbage-collected. In your example, the grouping operator () coerces its content into an expression, therefore the function is an expression and can be called immediately as such.
One important thing to note about the difference between my first foo and bar example though is hoisting. If you don't know what that it is, a quick Google search or two should tell you, but the quick and dirty definition is that hoisting is JavaScript's behavior to bring declarations (variables and functions) to the top of a scope. These declarations usually only hoist the identifier but not its initialized value, so the entire scope will be able to see the variable/function before it is assigned a value.
With function definitions this is not the case, here the entire declaration is hoisted and will be visible throughout the containing scope.
console.log("lose your " + function() {
fiz(); //will execute fiz
buzz(); //throws TypeError
function fiz() {
console.log("lose your scoping,");
}
var buzz = function() {
console.log("and win forever");
};
return "sanity";
}()); //prints "lose your scoping, lose your sanity"
Jslint will call out errors if functions are defined out of order.
Obviously jslint is strict, but I wonder if there are any benefits to putting functions in order.
By that I mean defining them before they are called.
Function definitions (and var statements) are hoisted to the top of their closure. In other words, code is executing in an order that is not the same as what you wrote.
Now, there is nothing more "wrong" about it than leaving off the ; at the end of lines, but jsLint is designed to test the human-readability of the code. Jumping around isn't human-readable, so it's considered invalid.
If you define function before calling it, the code can be handled by one pass compiler, otherwise, you need a multi-pass compiler (which is slower in general).
Maybe there are some one pass JavaScript compilers out there (however, I don't know any).
I always think JSLint shows that error because it wants to make sure your code can run in a one pass compiler successfully
Depends.
This will succeed:
var x = y();
function y() { return 9; }
But this will fail:
var x = y();
var y = function() { return 9; };
When the first script is interpreted it will see function y and will make that function available throughout its scope (being the global scope in that example).
Whereas with the second example a function is assigned to y. And just like any other variable the order matters.
Many programming languages require a special user-written function that marks the begin
of the execution. For example, in C this function must always have the name main(). In
JavaScript, however, such a function is not required.
What are the logical reason for the absence of such a dedicated top level function in JavaScript? I know this is some kind of theoretical question, but I cannot find an answer online.
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.
JavaScript is event-driven, the program written in JavaScript doesn't have a start and an end. You can compare it to any desktop UI toolkit, where you handle button clicks and key presses, but there is no obvious main once the program is initialized.
For instance there is a window.onload event that is triggered when the page is loaded - and which you can handle.
in a scripting language, the code is executed from the first line in the file to the end as if it was being typed into an interpreter. (this doesn't preclude parsing and compiling the code as long as those process don't effect the denotational semantics described.)
Javascript,python and PHP there are scripting language. These programming languages are not using main() function.
You already know the answer
In JavaScript, however, such a function is not required!
JavaScript is scripting language while C needs to be compiled.
Today I had a discussion with a colleague about nested functions in Javascript:
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
d = 'Bound to global object.'
}
In this example, trials point out that b is not reachable outside the body of a, much like c is. However, d is - after executing a(). Looking for the exact definition of this behaviour in the ECMAScript v.3 standard , I didn't find the exact wording I was looking for; what Sec.13 p.71 does not say, is which object the function object created by the function declaration statement is to be bound to. Am I missing something?
This is static scoping. Statements within a function are scoped within that function.
Javascript has a quirky behavior, however, which is that without the var keyword, you've implied a global variable. That's what you're seeing in your test. Your "d" variable is available because it is an implied global, despite being written within the body of a function.
Also, to answer the second part of your question: A function exists in whatever scope it is declared, just like a variable.
Sidenote:
You probably don't want global variables, especially not implied ones. It's recommended that you always use the var keyword, to prevent confusion and to keep everything clean.
Sidenote:
The ECMA Standard isn't probably the most helpful place to find answers about Javascript, although it certainly isn't a bad resource. Remember that javascript in your browser is just an implementation of that standard, so the standards document will be giving you the rules that were (mostly) followed by the implementors when the javascript engine was being built. It can't offer specific information about the implementations you care about, namely the major browsers. There are a couple of books in particular which will give you very direct information about how the javascript implementations in the major browsers behave. To illustrate the difference, I'll include excerpts below from both the ECMAScript specification, and a book on Javascript. I think you'll agree that the book gives a more direct answer.
Here's from the ECMAScript Language Specification:
10.2 Entering An Execution Context
Every function and constructor call
enters a new execution context, even
if a function is calling itself
recursively. Every return exits an
execution context. A thrown exception,
if not caught, may also exit one or
more execution contexts.
When control
enters an execution context, the scope
chain is created and initialised,
variable instantiation is performed,
and the this value is determined.
The
initialisation of the scope chain,
variable instantiation, and the
determination of the this value depend
on the type of code being entered.
Here's from O'Reilly's Javascript: The Definitive Guide (5th Edition):
8.8.1 Lexical Scoping
Functions in JavaScript are lexically
rather than dynamically scoped. This
means that they run in the scope in
which they are defined, not the scope
from which they are executed. When a
function is defined, the current scope
chain is saved and becomes part of
the internal state of the function.
...
Highly recommended for covering these kinds of questions is Douglas Crockford's book:
JavaScript, The Good Parts http://oreilly.com/catalog/covers/9780596517748_cat.gif
Javascript, The Good Parts, also from O'Reilly.
As I understand it, these are equivalent as far as scoping is concerned:
function a() { ... }
and
var a = function() { ... }
It seems important to note that while d is being created as a "global", it is in reality being created as a property of the window object. This means that you could inadvertently be overwriting something that already exists on the window object or your variable might actually fail to be created at all. So:
function a() {
d = 'Hello World';
}
alert(window.d); // shows 'Hello World'
But you cannot do:
function a() {
document = 'something';
}
because you cannot overwrite the window.document object.
For all practical purposes you can imaging that all of your code is running in a giant with(window) block.
Javascript has two scopes. Global, and functional. If you declare a variable inside a function using the "var" keyword, it will be local to that function, and any inner functions. If you declare a variable outside of a function, it has global scope.
Finally, if you omit the var keyword when first declaring a variable, javascript assumes you wanted a global variable, no matter where you declare it.
So, you're calling function a, and function a is declaring a global variable d.
...
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
d = 'Bound to global object.'
}
without being preceded by var, d is global. Do this to made d private:
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
var d = 'Bound to local object.'
}