Javascript hoisting - David Shariff quiz - javascript

The question is, what will the following alert:
function bar() {
return foo;
foo = 10;
function foo() {}
var foo = '11';
}
alert(typeof bar());
and the answer is, function.
My questions:
Isn't bar() being replaced by its return value? If no, why?
Isn't foo = 10; being hoisted to the top? (hoisting)

You can look at it this way:
function bar() {
var foo = function() {};
return foo; // function ends here
foo = 10;
foo = '11';
}
The other two assignment statements aren't happening.

Only declarations are hoisted in JavaScript.
For function declarations, that includes their entire statement body (which is empty in the case of foo). However, with vars, the assignments aren't considered part of the declaration and will remain where the statement was placed. (2)
To the engine, bar() appears to be:
function bar() {
// hoisted
function foo() {}
var foo; // no-op, `foo` was already declared by `function foo() {}`
// remaining statements
return foo;
// unreachable code following a `return`
foo = 10;
foo = '11'; // separated from `var foo;`
}
The resulting typeof being function is referring to the type of function foo() {}, a reference to which is what bar() returns. (1)
alert(bar().toString()); // "function foo() {}"

Related

javascript hoisting: Explain the output

let s = new Set("Foood");
console.log(s); //{}
console.log(typeof foo); // function
var foo = "string";
foo = 34;
function foo() {
//some code
}
console.log(typeof foo); // number
I was going through a codebase and came across this sort of codebase, can anyone explain the output of "typeof" operator in this code. Why for the first time it gave "function" and "number" second time.
As requested the snippet will be interpreted as following. As you can see the variables and functions get moved to the top.
However variables initialised with let or const will throw a ReferenceError if they are used before the point they were declared. More on that in this post
var foo, s;
function foo() {
//some code
}
s = new Set("Foood");
console.log(s); //{}
console.log(typeof foo); // function
foo = "string";
foo = 34;
console.log(typeof foo); // number
As you asked in the comments, here is the function after hoisting:
function foo() {
//some code
}
let s = new Set("Foood");
console.log(s); //{}
console.log(typeof foo); // function
var foo = "string";
foo = 34;
console.log(typeof foo); // number
function foo() {} is moved up to the top of it's scope - which, in this case, is the top of the page. When the first typeof foo is called, foo is a function. foo is then overwritten, and becomes 34. The second typeof returns number because foo = 34

JavaScript fundamentals confusion [duplicate]

This question already has answers here:
Javascript function scoping and hoisting
(18 answers)
Closed 6 years ago.
Hi I am trying to understand the JavaScript fundamentals, and stuck in one condition.
var foo = 1;
function bar(){
foo = 10;
return;
function foo(){}
}
bar();
alert(foo);
Here alert(foo), will give me 1, and I know after return statement, function foo() will not execute. But now if change the code:
var foo = 1;
function bar(){
foo = 10;
return;
}
bar();
alert(foo);
In bar function, If I will remove function foo(). then alert(foo) will give me 10
Please help, if someone can explain me why?
This is called Javascript hoisting
I will try to explain it in details.. This is what we have
var foo = 1;
function bar(){
foo = 10;
return;
function foo(){}
}
bar();
alert(foo);
The interpreter will rewrite this as
var foo = 1;
function bar(){
function foo(){} // this is also equal to var foo = function(){};
foo = 10;
return;
}
bar();
alert(foo);
So now explaining you the hoisted code.
var foo = 1; // global variable;
function bar(){
var foo = function(){}; // foo is local variable of type function
foo = 10; // foo is changed to hold a number
return;
}
bar();
alert(foo); // you alert global variable.
As you can see if the code function foo(){} is present it is treated as a local variable within the bar() scope and any change to the foo is treated as a local variable change..
When you have function foo(){} in your bar() you are not even touching the global variable.. hence alerts 1.
When you don't have function foo(){} you are touching the global variable and hence alerts 10.
Now I hope you understand the output..
I know after return statement ,function foo() will not execute.
That's not true.
Function declarations are hoisted.
function foo(){} creates a local variable called foo (assigning the new function to it) and then foo = 10 overwrites it. You never test the value of that foo variable though.
In bar function , If I will remove function foo(). then alert(foo) will give me 10
You no longer have a local variable called foo so you are overwriting the global variable with the same name.
Compare:
(function() {
console.log("Version 1");
var foo = 1;
function bar() {
console.log("At top of bar, foo is " + foo);
foo = 10;
console.log("After assignment in bar, foo is " + foo);
return;
function foo() {}
}
bar();
console.log("Global foo is " + foo);
}());
(function() {
console.log("Version 2");
var foo = 1;
function bar() {
console.log("At top of bar, foo is " + foo);
foo = 10;
console.log("After assignment in bar, foo is " + foo);
return;
}
bar();
console.log("Global foo is " + foo);
}());
When you write this function :
function bar(){
foo = 10;
return;
function foo(){}
}
The javascript read this :
function bar(){
function foo(){}
foo = 10;
return;
}
The function foo is created into your local function bar. And when you write foo = 10,You overwrite the function foo in the local scope and not the global variable.
So your alert give you 1 because you never update the global variabe.
The problems here are hoisting and closure .
The declaration function foo(){} is hoisted, meaning in this case, even though it is written at the end of the function, it will be available everywhere within the scope, including before it's definition.
if function foo(){} IS NOT present, the statement foo = 10; overwrites the foo defined in the global scope. Therefore the global foo === 10.
If function foo(){} IS present, the statement foo = 10; just overwrites the function foo in the local scope, the global foo won't get touched hence global foo === 1
var foo = 1;
function bar(){
console.log(typeof foo) // function
return;
function foo() {}
}
bar();
alert(foo);
Opposed to:
var foo = 1;
function bar(){
console.log(typeof foo) // number
return;
// function foo() {}
}
bar();
alert(foo);
So basically what is happening is as if you have declared var foo = 10
because function declaration in javascript are hoisted up top
complier sees your code as follows .
var foo = 1;
function bar(){
var foo;
foo = 10;
return;
function foo(){}
}
bar();
alert(foo);
so in fact foo = 10 never overwrites the global foo;
it is kept local to the function .
so alert will get passed the global one .
In addition to my previous answer in the same thread I am
adding another answer to put in more details about the Hoisting
feature in JavaScript as the previous answer is already accepted by the OP for its content.
First lets get comfortable with what scoping is
Scoping in JavaScript
One of the sources of most confusion for JavaScript beginners is scoping. Actually, it’s not just beginners. I’ve met a lot of experienced JavaScript programmers who don’t fully understand scoping. The reason scoping is so confusing in JavaScript is because it looks like a C-family language. Consider the following C program:
#include <stdio.h>
int main() {
int x = 1;
printf("%d, ", x); // 1
if (1) {
int x = 2;
printf("%d, ", x); // 2
}
printf("%d\n", x); // 1
}
The output from this program will be 1, 2, 1. This is because C, and the rest of the C family, has block-level scope. When control enters a block, such as the if statement, new variables can be declared within that scope, without affecting the outer scope. This is not the case in JavaScript. Try the following in Firebug:
var x = 1;
console.log(x); // 1
if (true) {
var x = 2;
console.log(x); // 2
}
console.log(x); // 2
In this case, Firebug will show 1, 2, 2. This is because JavaScript has function-level scope. This is radically different from the C family. Blocks, such as if statements, do not create a new scope. Only functions create a new scope.
To a lot of programmers who are used to languages like C, C++, C#, or Java, this is unexpected and unwelcome. Luckily, because of the flexibility of JavaScript functions, there is a workaround. If you must create temporary scopes within a function, do the following:
function foo() {
var x = 1;
if (x) {
(function () {
var x = 2;
// some other code
}());
}
// x is still 1.
}
This method is actually quite flexible, and can be used anywhere you need a temporary scope, not just within block statements. However, I strongly recommend that you take the time to really understand and appreciate JavaScript scoping. It’s quite powerful, and one of my favorite features of the language. If you understand scoping, hoisting will make a lot more sense to you.
Declarations, Names, and Hoisting
In JavaScript, a name enters a scope in one of four basic ways:
Language-defined: All scopes are, by default, given the names this and arguments.
Formal parameters: Functions can have named formal parameters, which are scoped to the body of that function.
Function declarations: These are of the form function foo() {}.
Variable declarations: These take the form var foo;.
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:
Ex:
function foo() {
bar();
var x = 1;
}
is actually interpreted like this:
function foo() {
var x;
bar();
x = 1;
}
It turns out that it doesn’t matter whether the line that contains the declaration would ever be executed. The following two functions are equivalent:
function foo() {
if (false) {
var x = 1;
}
return;
var y = 1;
}
function foo() {
var x, y;
if (false) {
x = 1;
}
return;
y = 1;
}
Notice that the assignment portion of the declarations were not hoisted. Only the name is hoisted. This is not the case with function declarations, where the entire function body will be hoisted as well. But remember that there are two normal ways to declare functions. Consider the following JavaScript:
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();
In this case, only the function declaration has its body hoisted to the top. The name ‘foo’ is hoisted, but the body is left behind, to be assigned during execution.
That covers the basics of hoisting. The complete 100% credit of this answer goes to ben cherry. I didnt want to post this link in my answer because the links might break and I found this completely informative and a must read for any javascript developer.

What will the reference be when a variable and function have the same name?

I have a variable named foo and function named foo.
//variable followed by function declaration
var foo="bar";
function foo(){
return "bar";
}
//function declaration followed by variable
function foo(){
return "bar";
}
var foo="bar";
//When I call foo it returns string bar;
//When I enquired foo() it throws error
What's happening here?Why does the variable name override function declaration?
When I call foo it returns string bar;
Function declarations are hoisted to the top of their scope. The function definition are moved above by the compiler. And then the variable is overwriting to string.
Code is equivalent as
function foo() {
return "bar";
}
// Overwriting the value
var foo = "bar"
So, in both the cases, the output will be 'bar'.
Note that function expressions are not hoisted.
For more information on function hoisting, see Javascript function scoping and hoisting
When I enquired foo() it is undefined
foo here is not a function, it's a string. So, foo() will throw an error
Uncaught TypeError: a is not a function(…)
In a clearer and more explicit way of declaring variables, the latter will take account:
var foo = "bar";
var foo = function () {
return "bar";
};
console.log(foo);
output is a function
and the reversal:
var foo = function () {
return "bar";
};
var foo = "bar";
console.log(foo);
has "bar" as output.
In JavaScript, functions are processed upon entering the corresponding scope.
The variables are processed when the interpreter gets to their declaration.
Therefore in your example, the functions are processed first, the name foo is used by the last function and then overwritten by the variables.
Note that if you declare your function like this
var foo = function() {}
it is actually not processed at the beginning and also overwriting the variables declared beforehand.
var foo="bar";
var foo = function(){
return "bar";
};
They are the same. Don't miss to put ; in the end of line.
both cases will return the string "bar"
basically javascript grabs all functions and put them in the top of the file
its called hoisting .
so the string declaration will overwrite the function expression in both cases ;

How to get the current running function name when declared with "foo = function(){...}"?

In this situation, arguments.callee.name get nothing.
foo = function(){
console.log(arguments.callee.name);
}
Is there any solution?
You didn't name it, thus it has no name.
foo = function(){
return (arguments.callee.name);
};
bar = function foobar() {
return (arguments.callee.name);
};
function foobar () {
return (arguments.callee.name);
}
console.log(foo()); //""
console.log(bar()); //"foobar"
console.log(foobar()) //"foobar"
The difference between foo() and foobar() is that foo() is a function expression, whereas foobar() is a declared function. The difference between foo() and bar() and is that one has a name, the other doesn't. Both are function expressions. Declared functions need a name, function expressions do not. See this canonical question for more info:
var functionName = function() {} vs function functionName() {}

Scope of variables (Hoisting) in Javascript

One of my friends was taking an online quiz and he asked me this question which I could not answer.
var global = false;
function test() {
global = true;
return false;
function global() {}
}
console.log(global); // says false (As expected)
test();
console.log(global); // says false (Unexpected: should be true)
If we assume that functions are hoisted at the top along with var variables, let's try this one.
var foo = 1;
function bar() {
return foo;
foo = 10;
function foo() {}
var foo = 11;
}
bar();
console.log(foo); //says 1 (But should be 11) Why 1 this time ??
Here is a JSBin Demo and JSBIN Demo2 to play with.
PS: If we remove function global() {} from test(), then it runs fine. Can somebody help me understand why is this happening ?
var statements and function declaration statements are "hoisted" to the top of their enclosing scope.
Therefore, the function global(){} in your function creates a local global name.
Assigning to global inside your functions binds to this local name. Here's how you can "rewrite" it using hoisting to understand how the compiler sees it:
function test() {
var global = function() {}; // hoisted; 'global' now local
global = true;
return false;
}
I'll answer the second part of your question,
If we assume that functions are hoisted at the top along with var variables
bar();
console.log(foo); //says 1 (But should be 11) Why 1 this time ??
You should try console.log(bar()); console.log(foo); instead. However, what hoisting does to your function is this:
function bar() {
var foo;
function foo() {}
return foo;
foo = 10;
foo = 11;
}
So you should expect to get the function returned, since your variable assignments are after the return statement. And both the var and the function declaration make foo a local variable, so the global foo = 1 is never changed.

Categories

Resources