Javascript- Variable Hoisting - javascript

This is a simple snippet, I just dont understand something.
The below code outputs 12, I understand that, because the var foo = 12; replaces the previous declaration of the variable.
<script>
var foo = 1;
function bar(){
if (!foo) {
var foo = 12;
}
alert(foo);
}
bar();
</script>
In the below code, it alerts 1 , which means the variable declared outside the function is accessible inside the function.
<script>
var foo = 1;
function bar(){
alert(foo);
}
bar();
</script>
But, in the below code, why it alerts undefined ?? I thought, it will alert 1, I am just assigning the previously declared variable to the new one.
<script>
var foo = 1;
function bar(){
if (!foo) {
var foo = foo;
}
alert(foo);
}
bar();
</script>

Variable declarations are pushed to the start of the function.
Therefore in reality the following is happening:
function bar(){
var foo;
if (!foo) {
foo = foo;
}
alert(foo);
}
Therefore you would need to change this to use window.foo so that you're referring to the global property rather than the function's property:
var foo = 1;
function bar(){
var foo;
if (!window.foo) {
foo = window.foo;
}
alert(foo);
}
bar();

Hoisting is slightly tricky. Function declarations are hoisted with the function assignment, but variable declarations are hoisted without the variable assignment. So the execution order of code is actually:
var foo;
var bar = function bar(){
var foo; // undefined
if (!foo) { // true
foo = foo; // foo = undefined
}
alert(foo);
}
foo = 1;
bar();
You could either use window.foo if you want to refer to the global variable foo, or better, just use a different variable name:
var foo = 1;
function bar(){
var baz = foo;
alert(baz);
}
bar();

The below code outputs 12, I understand that, because the var foo =
12; replaces the previous declaration of the variable.
var foo = 1;
function bar(){
if (!foo) {
var foo = 12;
}
alert(foo);
}
bar();
You are right because local variable overriding the global one.
In the below code, it alerts 1 , which means the variable declared
outside the function is accessible inside the function.
var foo = 1;
function bar(){
alert(foo);
}
bar();
You are correct. foo is declare in global scope so is accessible fron anywhere.
But, in the below code, why it alerts undefined ?? I thought, it will
alert 1, I am just assigning the previously declared variable to the
new one.
var foo = 1;
function bar(){
if (!foo) {
var foo = foo;
}
alert(foo);
}
bar();
This is a bit different. You are declaring a global variable and a local one with the same name. When your JavaScript program execution enters a new function, all the variables declared anywhere in the function are moved (or elevated, or hoisted) to the top of the function.
Another example:
var a = 123;
function f() {
var a; // same as: var a = undefined;
alert(a); // undefined
a = 1;
alert(a); // 1
}
f();

In javascript, until the ES5 specification, the scope is implemented only in terms of function body. The concept of block scope doesn't exist (really, will be implemented in the next javascript with the let keyword).
So, if you declare a variable var something; outside from function body, it will be global (in browsers global scope is the scope of the window object).
global variables
var something = 'Hi Man';
/**
* this is equal to:
**/
window.something = 'Hi Man';
If your code doesn't run in strict mode, there is another way to declare a global variable: omitting the var keyword. When the var keyword is omitted the variable belongs (or is moved) to the global scope.
example:
something = 'Hi Man';
/**
* this is equal to:
**/
function someFunction() {
something = 'Hi Man';
}
Local Variables
Because the non-existence of block scopes the only way to declare a local variable is to define it in a function body.
Example
var something = 'Hi Man'; //global
console.log('globalVariable', something);
function someFunction() {
var something = 'Hi Woman';
console.log('localVariable', something);
/**
* defining variable that doesn't exists in global scope
**/
var localSomething = 'Hi People';
console.log('another local variable', localSomething);
}
someFunction();
console.log('globalVariable after function execution', something);
try {
console.log('try to access a local variable from global scope', localSomething);
} catch(e) { console.error(e); }
As you can see in this example, local variables don't exist outside from their scope. This means another thing... If you declare, with the var keyword, the same variable in two different scopes you'll get two different variables not an override of the same variable (name) defined in the parent scope.
If you want to "override" the same variable in a child scope you have to use it without the var keyword. Because of the scope chain if a variable dosn't exist in a local scope it will be searched on their parent scope.
Example
function someFunction() {
something = 'Hi Woman';
}
var something = 'Hi Man';
console.log(1, 'something is', something);
someFunction();
console.log(1, 'something is', something);
Last thing, variable hoistment.
As I wrote below, at the moment, there isn't any way to declare a variable in some point of your code. It is always declared at the start of it scope.
Example
function someFunction() {
// doing something
// doing something else
var something = 'Hi Man';
}
/**
* Probably you expect that the something variable will be defined after the 'doing
* something else' task, but, as javascript works, it will be defined on top of it scope.
* So, the below snippet is equal to:
**/
function someFunction1() {
var something;
// doing something
// doing something else
something = 'Hi Man';
}
/**
* You can try these following examples:
*
* In the someFunction2 we try to access on a non-defined variable and this throws an
* error.
*
* In the someFunction3, instead, we don't get any error because the variable that we expect to define later will be hoisted and defined at the top, so, the log is a simple undefined log.
**/
function someFunction2() {
console.log(something);
};
function someFunction3() {
console.log('before declaration', something);
var something = 'Hi Man';
console.log('after declaration', something);
}
This happens because in javascript there are two different steps of a variable declaration:
Definition
Initialization
And the function3 example becomes as following:
function3Explained() {
var something; // define it as undefined, this is the same as doing var something = undefined;
// doing something;
// doing something else;
something = 'Hi Man';
}

IMHO it doesn't have anything to do with function declaration and hoisting ,
declaring the var with var inside function you are creating a variable in the function's isolated scope, this is why you get undefined.
var foo = 1;
function funcOne() {
var foo = foo;
alert('foo is ' + foo);
};
funcOne();
var bau = 1;
function funcTwo() {
bau = bau;
alert('bau is ' + bau);
};
funcTwo();
fiddle

Related

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.

Scope in JavaScript behaviour

This is a simple script that'll log the content of text from a Photoshop file.
var numOfLayers = app.activeDocument.layers.length;
var resultStr = "";
doAllLayers();
alert(resultStr);
function addToString(alayer)
{
if (alayer.kind == "LayerKind.TEXT")
{
var c = alayer.textItem.contents;
resultStr += c;
}
}
// main loop
function doAllLayers()
{
for (var i = numOfLayers -1; i >= 0; i--)
{
var thisLayer = app.activeDocument.layers[i];
addToString(thisLayer);
}
}
It works fine but I really should be passing a string into the function to add to itself, however it works.
How does the scope of JavaScript allow this to happen? Are declared local variables still accessed by functions or is it another trick I'm missing?
Here are some basic rules to variable scoping in JavaScript:
If defined with the var keyword, the variable is function-scoped. That is, the variable will be scoped to either the closest containing function, or to the global context if there is no containing function.
Example:
// globally-scoped variable (no containing function)
var foo = 'bar';
function test() {
// function-scoped variable
var foo2 = 'bar2';
if (true) {
// still function-scoped variable, regardless of the if-block
var foo3 = 'bar3';
}
// see?
console.log(foo3); // --> 'bar3'
}
If defined with the let keyword (ES6+), then the variable is block-scoped (this behavior more closely resembles most other C-family syntax languages). Example:
// error: top level "let" declarations aren't allowed
let foo = 'bar';
function test() {
// block-scoped variable (function are blocks, too)
let foo2 = 'bar2';
if (true) {
// block-scoped variable (notice the difference
// from the previous example?)
let foo3 = 'bar3';
}
// uh oh?
console.log(foo3); // --> ReferenceError: foo3 is not defined
}
If defined with neither the var or let keywords (e.g., foo = bar), then the variable is scoped to the global context. Example:
// globally-scoped variable
foo = 'bar';
function test() {
// also globally-scoped variable (no var or let declaration)
foo2 = 'bar2';
if (true) {
// still a globally-scoped variable
foo3 = 'bar3';
}
}
test();
console.log(foo, foo2, foo3); // 'bar', 'bar2', 'bar3'
In all of these cases, functions defined within scope of a variable still have access to the variable itself (technically you're creating a closure, as the numOfLayers and resultStr variables are lexically in scope of your addToString and doAllLayers functions).
Please note that the scoping rules are technically a little more nuanced than this, but you're better off reading a more in-depth article at that point.
You have defined var resultStr = ""; outside function which is a global variable. you can access this global variable inside addToString() and start concatenating to it. Note that inside the method you have not declared var resultStr = ""; else it would have been a different variable local to that method.

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.

Declaring variables with this or var?

What is the difference between declaring a variable with this or var ?
var foo = 'bar'
or
this.foo = 'bar'
When do you use this and when var?
edit: is there a simple question i can ask my self when deciding if i want to use var or this
If it is global code (the code is not part of any function), then you are creating a property on the global object with the two snippets, since this in global code points to the global object.
The difference in this case is that when the var statement is used, that property cannot be deleted, for example:
var foo = 'bar';
delete foo; // false
typeof foo; // "string"
this.bar = 'baz';
delete bar; // true
typeof bar; "undefined"
(Note: The above snippet will behave differently in the Firebug console, since it runs code with eval, and the code executed in the Eval Code execution context permits the deletion of identifiers created with var, try it here)
If the code is part of a function you should know that the this keyword has nothing to do with the function scope, is a reserved word that is set implicitly, depending how a function is called, for example:
1 - When a function is called as a method (the function is invoked as member of an object):
obj.method(); // 'this' inside method will refer to obj
2 - A normal function call:
myFunction(); // 'this' inside the function will refer to the Global object
// or
(function () {})();
3 - When the new operator is used:
var obj = new Constructor(); // 'this' will refer to a newly created object.
And you can even set the this value explicitly, using the call and apply methods, for example:
function test () {
alert(this);
}
test.call("hello!"); //alerts hello!
You should know also that JavaScript has function scope only, and variables declared with the var statement will be reachable only within the same function or any inner functions defined below.
Edit: Looking the code you posted to the #David's answer, let me comment:
var test1 = 'test'; // two globals, with the difference I talk
this.test2 = 'test'; // about in the beginning of this answer
//...
function test4(){
var test5 = 'test in function with var'; // <-- test5 is locally scoped!!!
this.test6 = 'test in function with this'; // global property, see below
}
test4(); // <--- test4 will be called with `this` pointing to the global object
// see #2 above, a call to an identifier that is not an property of an
// object causes it
alert(typeof test5); // "undefined" since it's a local variable of `test4`
alert(test6); // "test in function with this"
You can't access the test5 variable outside the function because is locally scoped, and it exists only withing the scope of that function.
Edit: In response to your comment
For declaring variables I encourage you to always use var, it's what is made for.
The concept of the this value, will get useful when you start working with constructor functions, objects and methods.
If you use var, the variable is scoped to the current function.
If you use this, then you are assigning a value to a property on whatever this is (which is either the object the method is being called on or (if the new keyword has been used) the object being created.
You use var when you want to define a simple local variable as you would in a typical function:-
function doAdd(a, b)
{
var c = a + b;
return c;
}
var result = doAdd(a, b);
alert(result);
However this has special meaning when call is used on a function.
function doAdd(a, b)
{
this.c = a + b;
}
var o = new Object();
doAdd.call(o, a, b);
alert(o.c);
You note the first parameter when using call on doAdd is the object created before. Inside that execution of doAdd this will refer to that object. Hence it creates a c property on the object.
Typically though a function is assigned to a property of an object like this:-
function doAdd(a, b)
{
this.c = a + b;
}
var o = new Object();
o.doAdd = doAdd;
Now the function can be execute using the . notation:-
o.doAdd(a, b);
alert(o.c);
Effectively o.doAdd(a, b) is o.doAdd.call(o, a, b)
var foo = 'bar'
This will scope the foo variable to the function wrapping it, or the global scope.
this.foo = 'bar'
This will scope the foo variable to the this object, it exactly like doing this:
window.foo = 'bar';
or
someObj.foo = 'bar';
The second part of your question seems to be what is the this object, and that is something that is determined by what context the function is running in. You can change what this is by using the apply method that all functions have. You can also make the default of the this variable an object other than the global object, by:
someObj.foo = function(){
// 'this' is 'someObj'
};
or
function someObj(x){
this.x=x;
}
someObj.prototype.getX = function(){
return this.x;
}
var myX = (new someObj(1)).getX(); // myX == 1
In a constructor, you can use var to simulate private members and this to simulate public members:
function Obj() {
this.pub = 'public';
var priv = 'private';
}
var o = new Obj();
o.pub; // 'public'
o.priv; // error
Example for this and var explained below:
function Car() {
this.speed = 0;
var speedUp = function() {
var speed = 10; // default
this.speed = this.speed + speed; // see how this and var are used
};
speedUp();
}
var foo = 'bar'; // 'var can be only used inside a function
and
this.foo = 'bar' // 'this' can be used globally inside an object

Pass in jQuery/plainJS variables/functions of a current scope to anonymous function called from current scope

How to pass current scope variables and functions to the anonymous function in plain Javascript or in jQuery (if it's specific for frameworks).
For example:
jQuery.extend({
someFunction: function(onSomeEvent) {
var variable = 'some text'
onSomeEvent.apply(this); // how to pass current scope variables/functions to this function?
return null;
_someMethod(arg) {
console.log(arg);
}
}
});
Should log in firebug everything from the function above:
jQuery.someFunction(function(){
console.log(this.variable); // or console.log(variable);
console.log(this._someMethod(1); // or jQuery.someFunction._someMethod(2);
});
Thanks!
Read about Scopes in JavaScript for example in "Java Script: The good parts".
In the Java Script there is only scope inside Functions.
If you specify your variable inside function with var you can't access them from outside of this function. This is way to make private variables in JavaScript.
You can use this variable, that point to current object you are in (this is not a scope itself). But! if you initiate function without new command, than this will point to outer scope (in most cases it's window object = global scope).
Example:
function foo(){
var a = 10;
}
var f = foo(); //there is nothing in f
var f = new foo(); //there is nothing in f
function bar(){
this.a = 10;
}
var b = new bar(); //b.a == 10
var b = bar(); //b.a == undefined, but a in global scope
Btw, check out syntax of apply method Mozilla docs/apply
So you can see, that fist argument is object, that will be this when your method will be called.
So consider this example:
function bar(){
console.log(this.a);
console.log(this.innerMethod(10));
}
function foo(){
this.a = 10;
this.innerMethod = function(a){
return a+10;
}
bar.apply(this);
}
var f = new foo(); // => you will get 10 and 20 in the console.
var f = foo(); // => you will still get 10 and 20 in the console. But in this case, your "this" variable //will be just a global object (window)
Maybe it's better to make
var that = this;
before calling apply method, but maybe it's not needed. not sure
So, this definitely will work:
function foo(){
console.log(this.a);
}
jQuery.extend({
somefunc: function(func){
this.a = 10;
func.apply(this);
}
});
$.somefunc(foo); //will print 10.
Before line 1:
var that = this;
Then change line 4:
onSomeEvent.apply(that);

Categories

Resources