My question is based on the example from a book "Object Oriented JavaScript" (page 81 - Lexical Scope)
So, i understand from this example ...
function f1(){var a = 1; f2();}
function f2(){return a;}
f1();
... that:
a is not defined
But, how f1 get's to know about f2, which is defined after f1 ?
This behavior raises a question:
How JavaScript interpreter works ?
I assume, that it:
scans the code and simply stores the functions, not assigned to any var, in a global environment
Invokes a function in ad-hoc way: when there is no such a function in a global environment, then complain.
Function declarations are processed upon entry into an executable context (e.g., the global context, or a function call), prior to any of the step-by-step code in the context being processed.
So in your code, these things happen (in this order):
A "variable object" is created for the execution context.
Entries (actually, literally, properties) on the "variable object" are created for every var and function declaration in the context (plus a few other things). In your case, that's f1 and f2. Initially the properties have the value undefined.
All function declarations are processed, and so:
The f1 function is defined and assigned to its property on the variable object.
The f2 function is defined and assigned to its property on the variable object.
The f1(); line is executed, calling the f1 function.
The f1 code refers to f2, which it gets from the variable object, and so it's what we expect it to be (a reference to the f2 function).
The more interesting version is this:
f1();
function f1(){var a = 1; f2();}
function f2(){return a;}
...which happens in exactly the same order listed above, because both of the declarations are handled before the first line of step-by-step code.
Function declarations are different from function expressions, which just like any other expression are evaluated when they're reached in the step-by-step execution of the code. A function expression is any time you create a function and use it as a right-hand value, e.g., assign the result to a variable or pass it into another function. Like this:
var f2 = function() {
};
or this
setTimeout(function() {
alert("Hi there");
}, 1000);
Note that we're using the result of the function statement as the right-hand value (in an assignment, or by passing it into a function). Those are not pre-processed upon entry into an execution context (e.g., not at Step 3 above), they're handled when the flow of code reaches them. Which leads to:
f1();
function f1(){var a = 1; f2();}
var f2 = function(){return a;};
...which fails, because f2 is undefined as of when it's called.
You can use a declared function's value as a right-hand value without turning it into a function expression (we do that all the time), so long as you do it in two separate statements. So:
alert("Beginning");
function foo() { ... }
setTimeout(foo, 100);
That happens in this order:
foo is created (since it's defined by a declaration).
The alert runs.
The setTimeout runs.
(Later) foo is called.
One last point: Although they should work, a function expression that includes a function name does not work reliably on all implementations and must, for now, be avoided:
var f = function foo() { ... }; // <== DON'T DO THIS
Or
setTimeout(function foo() { // <== DON'T DO THIS
}, 1000);
Internet Explorer, in particular, has issues with those, and other implementations have at various times as well.
More to explore:
Poor misunderstood var
Closures are not complicated (because it talks about variable objects and how symbols are resolved)
Anonymouses anonymous (talks more about named function expressions)
you don't have access to variable 'a' inside function f1, because function f2 is not defined inside f1 scope
if you define f2 inside f1:
function f1(){function f2(){return a;} var a = 1; f2();}
f1();
you don't have any problems
Related
Why is it that when I do the following:
var a = 1;
function foo(a) {
a = 2;
}
foo();
console.log(a); // a = 1
But I get a different result for the following:
var a = 1;
function foo() {
a = 2;
}
foo();
console.log(a); // a = 2
In the first example the function foo parameter a is shadowing the global variable a and thus the value of the global variable never changes. The code in the first example is equivalent to this one:
var a = 1;
function foo(x) {
x = 2;
}
In the second example you are referencing the global variable a inside the body of the function foo. Here no variable shadowing occurs so that you get the expected result - a is asigned the value of 2.
JavaScript doesn't really have "parameters on the left/right side." Your first example passes a parameter. Your second example uses a closure.
In programming languages, closures (also lexical closures or function closures) are techniques for implementing lexically scoped name binding in languages with first-class functions. Operationally, a closure is a record storing a function together with an environment: a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created. A closure—unlike a plain function—allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.
In your first example, the variable a inside the function foo is a different variable than a outside of the function. Changing foo's parameter a has no effect on the global variable a that gets passed to console.log.
In your second example, the variable a is not a parameter, but rather a part of the environment that is captured by the function foo. The log shows a modified value of a because the assignment inside foo and the console.log call outside of foo are actually referring to the same variable.
if a is passed in as an argument to that function -- then the value of a within that function is isolated and only accessible within that function. otherwise your a defined outside the function is shared across all functions and objects.
agree with #RomanPerekhrest -- read up.
**UPDATE in reply to comment **
var a = 1;
function foo(a) {
a = 2;
}
foo();
console.log(a); // a = 1
In the code above, the reference to a on lines 2 and 3 are a different variable from the a on lines 1 and 6. In the code from your comment, you are setting a to the value of x within the foo function. That's a bit different from the original question. No?
Code:
var funcExpression = function(){
alert("function expression");
}();
(function declarFunc(){
alert("declared func");
})();
The result is the function Expression is run first resulting in the alert "function expression" and the declared function is run second "declared func".
I know that during the hoisting process, declared functions are hoisted up entirely within their container and loaded into memory. Function expressions, however are not hoisted: they stay in the same place and are not loaded into memory until runtime(though the variable that points to the function expression is hoisted up and set to Undefined. (Please correct me if I have this concept wrong)
Since, the declared function is hoisted up above the function expression assignment, I would expect thus that the declared function is executed first: resulting in the alert "declared func" and then the function expression is executed afterwards: resulting in the second alert of "function expression".
However: it doesn't do what I expect. Thus, it seems like it has something to do with the immediate invocations of both the functions. Maybe the immediate invocations stay in the same order? Maybe after the hoisting process the code really looks like this:
var funcExpression = Undefined;
(function declarFunc(){
alert("declared func");
})
funcExpression = function(){
alert("function expression");
}();
(); // this executes declarFunc. Maybe declarFunc is hoisted up
// but the invoking part stays in the same place?
Solution after feedback and additional research
The answer is that BOTH of those functions are function expressions:
Code:
var funcExpression = function(){
alert("function expression");
}();
(function declarFunc(){
alert("declared func");
})();
so declareFunc() looks like a declared function, but since it is wrapped in parenthesis like that, it transforms it into a named function expression. The parenthesis following immediately evokes this function expression.
I was having trouble showing what the code looks like after the hoisting process because (function declarFunc(){...})() transforms into a named function expression due to those wrapping parenthesis. What this means is that outside of this named functions scope, we have no way to call it.
Example: If after these functions I did declarFunc() it will return with the error: ReferenceError: Can't find variable: declarFunc.
If we did want to make it possible to run this function expression then we would want to assign the function expression to a variable:
var foo = function declarFunc(){
alert("declared func");
};
Note: If we look at the console we will see that console.log(foo()) will return undefined, but the actions of the function will still take place. Just know that if no return statement is specified, then it implicitly returns undefined.
And now we can call on that function as many times as we would like with foo().
I read in a book about function declaration. The code goes like this.
function outer(){
assert(typeof inner === "function", "inner() in scope before declaration");
function inner(){}
assert(typeof inner === "function", "inner() in scope after declaration");
assert(typeof window.inner === "undefined", "inner() undefined in global space")
}
When the tests are run all the three statements are asserted true, showing that the inner() function existed in scope before its declaration. My concept about javascript is that the script is executed line by line and the functions should be declared before there call.
The question is how can the inner function exist in the scope before its declaration?
My concept about javascript is that the script is executed line by line and the functions should be declared before there call.
That's incorrect. In JavaScript, all function declarations in an execution context are processed upon entry into that execution context, before any step-by-step code is executed. So function declarations within functions are processed upon entry into the function when it gets called, and function declarations at global scope are processed before any global step-by-step code is executed. This is sometimes called "hoisting" (because the function declarations are effectively "hoisted" [lifted] up to the top of the scope they're declared in). (Side note: var is also hoisted, more on my blog: Poor misunderstood var.)
This is distinct from function expressions, which like all expressions, are evaluated in the step-by-step execution of the code.
Here's a function declaration:
function foo() { }
Here are three function expressions, note that in each case, they're used as right-hand values (e.g., they're assigned to a var or property, passed into a function, used in a containing expression, etc.), which is what makes them expressions rather than declarations:
var x = function foo() { };
obj = {
b: function bar() { }
};
doSomethingWith(function() { });
There I've shown two named function expressions and one anonymous function expression. If you're going to be writing code for IE8 and earlier, you may want to steer clear of named function expressions as IE's "JScript" interpreter gets them wrong; more (also my blog): Double take.
Javascript executes a function in two Pass, consider this :
There are two ways that you can use a function
1st: function quack(num){
for(var i=0; i<num ; i++)
{
console.log("quacking")
}
} - this is a function declaration.
2nd: var fly = function(num){
for(var i=0; i<num ; i++)
{
console.log("Flying!!!")
}
} - This is a function expression.
Now in the first pass the javascript looks for function declaration
which is
function quack(num){
for(var i=0; i<num ; i++)
{
console.log("quacking")
}
}
So it assigns quack's reference to a variable
which has the same name as that of the method ie.. quack .
So if you call quack() before you declare it, it works fine.
However in the 2nd pass it looks for function expression which
means you cannot call fly before evaluating it.
I hope this gives a better explanation.
In a comment on another thread I started, someone said this:
#adlwalrus yes. try this: var foo = function bar(){}; console.log(foo); But be aware that bar is only function name (what does it mean I'm not sure exactly myself) and not a reference to it, so you can't call it by doing bar(). And assigning (even named function) is not the same as declaring a function. Hoisting (bumping to top of the scope) only works for declarations, assignment will stay in place. – valentinas 6 hours ago
What purpose does a function name serve if you can't call it with bar()?
For the function to call itself.
var x = function y(val){
if (val){
console.log(val);
y(val-1);
}
};
x(5);
> 3
> 2
> 1
y(3);
> ReferenceError: y is not defined
You're referring to a named function expression. The spec requires that the name of such functions only be available within the scope of the new function. Spec quote:
The Identifier in a FunctionExpression can be referenced from inside
the FunctionExpression's FunctionBody to allow the function to call
itself recursively. However, unlike in a FunctionDeclaration, the
Identifier in a FunctionExpression cannot be referenced from and does
not affect the scope enclosing the FunctionExpression.
On the other hand, the result of that expression is a reference to the new function, which can be saved and referenced anywhere.
Lots of details here:
http://kangax.github.com/nfe/#named-expr
I'd read the whole thing.
As for benefits, another is that it makes them easier to identify in a debugger.
There are two ways to create a function in JavaScript, a "function declaration" and a "function expression." I believe it was Doug Crockford who explained it best when he pointed out that unless "function" is the very first set of characters on a given line, you're performing a function expression (not a declaration).
Function declarations are finicky creatures. You'll recognize them when you see them. They look like this:
function foo() { /* ... */ }
They're always given a name (it's requited) and the name is locally scoped to the lexical context under which the function is declared. So if you perform a function declaration in the global context, then the function can be referenced via it's name globally. If you do it within a function, the function's name can be referenced only within that function and any functions declared within that function.
I think the most important aspect of this method of declaring a function (one that is rarely commented on) is that the function initialization gets hoisted to the top of the current lexical context. Therefore, you should never, ever use a function declaration within a conditional, such as this:
//DON'T DO THIS!
if (x) {
function foo() { return 1; }
} else {
function foo() { return 2; }
}
foo(); //will always be 2, regardless of the value of x.
A function expression is slightly different. Often, they're directly assigned to a variable, like so:
var foo = function() { /* ... */ };
This is nearly identical to the function declaration above except that the initialization is not hoisted. So you can do the following:
var foo;
if (x) {
foo = function() { return 1; };
} else {
foo = function() { return 2; };
}
foo(); //will be 1 or 2, depending on the truthy-ness of x.
So, back to the original question. Function expressions can also have a name, though it's not required and it's not scoped to the context in which the function is declared (as with function declarations). Instead, it gets scoped to the function's own lexical context. This is very useful in some cases. My personal favorite is this pattern:
(function foo() {
//Do something.
setTimeout(foo, 1000);
}());
foo; //undefined
Because of the parenthesis before the word "function", this is a function expression and the name is scoped internally only. But that's okay, because we only need to call it internally (via setTimeout()). The result is that the function will execute once immediately, then will re-execute every second or so after it's finishes execution. This is safer than using setInterval() because it will wait until it's done executing before rescheduling itself, preventing overlaps that could cause missed executions and/or "domination" of the JavaScript thread.
Essentially, the use of a named function expression is limited, but when you need it, it's very powerful.
Suppose I have functions like:
function foo() {
}
function bar() {
}
I can write above as Object Literal notation:
var Baz = {
foo: function() {
},
bar: function() {
}
};
As far as I understand in the later case, an instance of Baz will be created when the script loads regardless if any Baz function is ever called. In the former case, function object is only created when that function is called. Am I correct about these assumptions?
If I am correct then the former would have higher performance (less memory) than the later in application where these functions are rarely called.
But the advantage of the later is that it gives greater modularity and lower global namespace pollution.
What is your take on this from your professional experience?
Is there a speed difference?
In the former case, function object is only created when that function is called.
No, the functions are created regardless.
Note that you can also do this:
function foo() {
}
function bar() {
}
var Baz = {
foo: foo,
bar: bar
};
Or this:
var Baz = (function() {
function foo() {
}
function bar() {
}
return {
foo: foo,
bar: bar
};
})();
The primary purpose of putting the functions on Baz as properties is to make them available as "methods" on Baz. This might be for convenience, for "namespacing", etc. In your first form (and my first form above), if that code is at global scope, foo and bar are added to the global scope, which can get pretty crowded pretty fast (esp. on browsers). In your second example, the only global symbol is Baz because the functions are anonymous. In my final example above, the only global symbol is Baz but the functions aren't anonymous, they have names that debuggers and stack traces can show you (which is a good thing; more here).
In terms of trying to optimize when functions get created, here's how it works: When execution enters a given context (the global context, or the context related to calling a function), these things are done:
A behind-the-scenes execution context object is created.
A behind-the-scenes variable object for that execution context is created.
In the case of a function context:
A property is added to the variable object for arguments (the array-like thing you can use to access arguments)
A property is added to the variable object for each of the function's named arguments, with the value of the argument
If the function has a name, its name is added as a property of the variable object and has the value of the function object.
Properties are created on the variable object for each variable declared with var in the execution context; their values are initially undefined (regardless of whether the var has an initializer on it).
Every function declaration in the context is processed. (Function expressions are not processed yet; more on the difference below.) A property on the variable object for each function name is created and receives the function object as its value.
Step-by-step code execution begins.
Like all expressions, function expressions are evaluated when they're encountered in the step-by-step flow.
var statements that have initializers (e.g., var a = 2;) are treated exactly like assignment statements (a = 2;); the var aspect of it was done much earlier. (var is frequently misunderstood. For instance, we had this question just yesterday.)
You'll note the difference above between function declarations and function expressions. You can tell which is which by looking to see whether you're using the result as a right hand value — that is, are you assigning the result to a variable, using it as the right-hand side of a property definition in an object literal, or passing it into a function. If you are, it's a function expression. If you're not, it's a function declaration.
Function declaration example:
function foo() {
}
Function expression example:
var foo = function() {
};
Another:
var Baz = {
foo: function() { }
};
(The foo line is a property declaration in an object literal that uses a function expression for the value.)
Named function expression example:
var f = function foo() { // <== Don't do this (more below)
};
Named function expressions should be valid, but they're poorly-supported by implementations in the wild (particularly IE) and so for now they must be avoided. More here.