JavaScript Internals 101: Hoisting variables and functions - javascript

Consider the following examples:
var company = 'Apple',
log = console.log;
function f1() {
log(company);
var company = 'Twilio';
log(company)
}
function f2() {
log(company());
function company() {
return 'Zynga';
}
}
function f3() {
log(company());
var company = function() { return 'RIM'; };
}
log(company);
log('---');
f1();
log('---');
f2();
log('---');
f3();
The output from firebug is:
"Apple"
---
undefined
"Twilio"
---
"Zynga"
---
TypeError: company is not a function
So why is hoisting in f3 giving me the error while others are working just fine?

Let's rewrite your f3 function to show what it would look like after variable hoisting:
function f3() {
log(company());
var company = function() { return 'RIM'; };
}
becomes:
function f3() {
var company; // declaration hoisted
log(company());
company = function() { return 'RIM'; };
}
Now you can see that you are attempting to execute an undefined variable, not a function (hence the "not a function" error).
Note that this is difference from the output of f2 because function declarations are hoisted as a unit.

The variable is hoisted, but setting it is not.
The value of company in f3 is not set until after log(company()) is called. You can see the same behavior in f1.

Related

JS variable hoisting inside closure

JS hoists all variables within scope so why does this code throw an exception:
(function() {
function i() {
console.log(a.a);
}
i();
var a = { a:1 };
})()
While this one works:
(function() {
var a = { a:1 };
function i() {
console.log(a.a);
}
i();
})()
What behavior of interpreter causes this?
The variable a is already visible, but its value {a:1} is not assigned until the var is reached by the execution. Things are somewhat different for local functions declared with function foo(){...} because the names are bound to the respective functions/closures before the execution starts.
If you call the closure i before assigning a a value you get the problem, however with
(function(){
function i(){
console.log(foo());
}
i();
function foo() { return 42; }
})();
the output is 42 and there's no error.
Note that this is true because the function statement is used... changing the code to
(function(){
function i(){
console.log(foo());
}
i();
var foo = function(){ return 42; }
})();
gives an error because in this case when i() is executed foo is not yet bound to the function (like in your case).

is a javascript function inside of a function globally scoped?

Here is an example of the test that I did:
function f1(var1){
alert('f1 called');
function f2(var2){
alert('f2 called');
}
this.data='something else';
this.f2 = f2;
}
f1.data='something';
f1.f3 = function(var3){
alert('f3 called');
}
console.log(f1); //shows the function
console.log(f1.data); //can have properties attached - cool
console.log(f1.f2(2)); //error: "f1.f2" is not a function
console.log(f1.f3(3)); //this works as expected
It appears that the function f2 inside f1 is local in scope. is there any equivalent way to call a function inside a function like this?
Unfortunately, this is bound to the global scope of window because you haven't instantiated an instance of f1 using new f1();
var f = new f1();
f.f2(); // Now works
Depending on what you are trying to achieve, there are a couple of patterns you can use to access the f2 function outside of f1. You can instantiate an f1 object using new:
function f1() {
this.f2 = function () { console.log('f2'); }
}
new f1().f2() //logs 'f2'
Or you can return the function f2 from the function f1:
function f1() {
return function f2() { console.log('f2'); }
}
f1()() //logs 'f2'
change code to:
function f1 (var1){
alert('f1 called');
};
f1.data='something else';
f1.f2 = function f2(var2){
alert('f2 called');
};

function statement and function expression inside if statement

Any reason why the following snippet shows different output in Firefox and Chrome:
var sayHo;
console.log(typeof(sayHey));
console.log(typeof(sayHo));
if(true) {
function sayHey() {
console.log("Hey, inside if");
};
sayHo = function() {
console.log("Ho, inside if");
};
}
else {
function sayHey() {
console.log("Hey, inside else");
};
sayHo = function() {
console.log("Ho, inside else");
};
}
sayHey();
sayHo();
Chrome(v31) outputs
function
undefined
Hey, inside else
Ho, inside if
Firefox(v26) outputs
undefined
undefined
Hey, inside if
Ho, inside if
I expected the same output what Chrome gave. During parse time, the function declaration inside will override the function declaration inside if. Because JavaScript will try to hoist both the function declarations, hence the override.
Firefox and Chrome use different JavaScript engines (SpiderMonkey and V8 respectively). The Chrome behaviour can be considered either a 'bug' or an 'ease of use feature'. In V8 function definitions inside if statements (rather than assignment of an anonymous function to a variable) are performed pre-execution. It's a design decision.
It all boils down to hoisting differences :
Function declarations and variable declarations are always moved (“hoisted”) invisibly to the top of their containing scope by the JavaScript interpreter. Function parameters and language-defined names are, obviously, already there. This means that code like this:
function foo() {
bar();
var x = 1;
}
is actually interpreted like this:
function foo() {
var x;
bar();
x = 1;
}
Consider this example :
function test() {
foo(); // TypeError "foo is not a function"
bar(); // "this will run!"
var foo = function () { // function expression assigned to local variable 'foo'
alert("this won't run!");
}
function bar() { // function declaration, given the name 'bar'
alert("this will run!");
}
}
test();
this code is equivalent to :
function test() {
function bar() { // function declaration, given the name 'bar'
alert("this will run!");
}
foo(); // TypeError "foo is not a function"
bar(); // "this will run!"
var foo = function () { // function expression assigned to local variable 'foo'
alert("this won't run!");
}
}
test();
Look what happened to the function declaration : it is hoisted.
Leet's look at simplier sample : http://jsbin.com/UKICENE/4/edit
console.log(typeof(sayHey));
if(true) {
function sayHey() {
console.log("Hey, inside if");
};}
sayHey();
This will yield function in chrome.
But it will yield undefined in FF.
Hoeever - deferring the calculationm via setTimeout will yield the same result as chrome :
console.log(typeof(sayHey));//undefined
setTimeout(function (){console.log(typeof(sayHey));},1000); //function
if(true) {
function sayHey() {
console.log("Hey, inside if");
};}
sayHey();
So , like Šime said , it delay the evaluation.
If you ask me , I think chrome is doing the right thing

Double nesting a function-valued return stops from entering the double nested function

Trying to understand the scope chain and execution context stack articles from David Shariff's Blog, I've tried to understand closures here
function foo() {
var a = 'private variable';
return function bar() {
alert(a);
}
}
var callAlert = foo();
callAlert(); // private variable
I just wanted to test if inner function has the variable object just from its parent or from the whole scope chain, so I added a nested function repeating the example:
function foo() {
var a = 'private variable';
return function bar() {
return function foobar() {
console.log(a);
};
};
}
var callAlert = foo();
callAlert(); //
And that is not giving any result. It seems the interpreter is not even entering the foobar() function. And the syntax is the same than its parent.
But it works if I divide the function declaration and execution.
function foo() {
var a = 'private variable';
return function bar() {
function ra() {
console.log(a);
};
return ra();
};
}
var callAlert = foo();
callAlert(); // private variable
And really I'm trying to guess why; where's the difference from bar() and foobar() functions.
PS - I'm testing on JSFiddle
function foo() {
var a = 'private variable';
return function bar() {
return function foobar() {
console.log(a);
};
};
}
Here you're returning a function that returns a function, so you need to call that new, doubly nested function
var callAlert = foo()();
DEMO
Or any variation on that theme
var getBar = foo();
var getFooBar = getBar();
getFooBar(); //private variable.
Updated demo
The second example works fine because you're still returning one function—a function that simple calls another function.
return function bar() {
function ra() {
console.log(a);
};
return ra();
};

Local and global scope of variables in JavaScript

I have tried reading other posts on the subject but no luck yet. In this code below why doesnt f2() have access to the var defined in f1(). Is not the var "name" a global to the function f2()? Should not f2() see the var "name"?
function f1() {
var name = "david";
function f2() {
document.writeln(name);
}
document.writeln(name);
}
f2(); // does not write out "david".
your f2() is only defined inside f1() scope. you can't call it globally
Javascript is function level scoped, not block scoped. A function has access to it's parent's function variables but not to variables defined in functions within it. You could return f2 from f1 and call it that way
function f1() {
var name = "david";
document.writeln(name);
return f2
function f2() {
document.writeln(name);
}
}
var f2 = f1();
f2();
You need to read up on Javascript Closures.
Here is a version of your snippet which demonstrates how you can access variables from outer function in an inner function (if you want to call inner function globally).
function f1()
{
var name = "david";
return function()
{
console.log(name);
}
}
var f2 = f1();
f2();

Categories

Resources