Friday, September 4, 2015

Advanced JavaScript Topics Part 2

We were discussing the let keyword in the Part 1 of this series. We discussed what the advantages and how we can use let keyword in the code. However, let keyword has a problem it does not support hoisting, means if you have declared a variable using let keyword in the mid of the block it would not be available in the part above the declaration of the let keyword.
So you always make sure that let is declared at the top of the block.
As we discussed earlier let keyword kind of Hack the scope implicitly. We can always write the code to make sure when we see we can explicitly identify that this block is a scope. The example given the in the Part 1 of this series used the implicit way. To use the explicit way do it like this

function foo(bar) {
    "use strict"
    let (test = bar) {
        console.log(test) // "bar"  
    }
    console.log(baz) // reference error
}

However, this syntax is rejected by the committee. we can use some other way to make sure we see the block scope in the code as we read the code.

function foo(bar) {
    "use strict"
    /*let */
    {
        let test = bar
        console.log(test) // "bar"  
    }
    console.log(baz) // reference error
}

This is one way to do it. Keyle Simpson have created this great tool to help you with block scoping it is called Let-er .


So, as we started to talk about tools you might want to take a look at traceur-compiler it generates ES 5 code from ES 6 code. As there is development going on in ES 6 you should start writing your code in ES 6 and use a transpiler to convert the ES 6 code to ES 5. You can use grunt-traceur . Other than this you might wanna take a look at the tools for ES 6.


Hoisting


Hoisting is a concept which is developed to understand how JavaScript works when we declare the variables and functions. Take a look at the code below


console.log(a);
console.log(b);
var a = 5;
var b = 10;

If you see the above code and try to infer the output of the first 2 consoles than you will think that there will be undeclared error, but not it will be not. Output of first 2 logs will be undefined. Why? You can think of the above code as below.

var a = 5;
var b = 10;
console.log(a);
console.log(b);
a = 5;
b = 10;

All the declarations will be moved to the top. Hence output will be undefined not undeclared. So if we say all the declarations that means variable declarations and function declarations. There are function declarations and function expressions.  Function declaration is

function foo()
{
}
And function expression is
var d = function() {
    console.log('hello');
}

Function expressions are not Hoisted.

So if we have a code like this

a = b();
b = d();
function b() {
    console.log('hello');
}
d = function() {
    console.log('world');
};

Here is the output of the code

function hoisting

function declarations are hoisted before the variable declarations


If you remember C/C++ programming? We use to write header files and put them at the top of our implementation files. That is manual hoisting, we are putting all the declarations at the top of the code. JavaScript do that for us implicitly.
Another use of Hoisting is mutual recursion.

this keyword


Each and every function in the JavaScript have reference to the current context of the function with this keyword. Function can have the current context depending upon

Default and Implicit Binding


Default binding is how the function is called. You can take a look at the code below and you should be able to understand the default binding.

This binding default

this binding

In above example you can see if we are calling the function hello without any decoration of object it is printing the global name variable. Which means this keyword is set to the global object. However, this is not true in strict mode. In Strict mode you will get an error as shown below

default binding error

Because in Strict mode value of this will be undefined. Not the global variable if we are calling the function without any decoration.

That’s default binding, we have called foo using obj1 and obj2 that is implicit binding.

With this I would like to point out something that we might think should work but it actually not possible take a look at the below code

function hello() {
                var one = "hello";
                world();
}
function world(){
                console.log(this.one + " world")
}
var one = "one";
hello();

think about what would be the output of the code?

You might think it would be “hello world” right? If you are right than you are wrong but if you are wrong than you are right.. J
Output of the above code will be “one world” because the binding if you try to understand the code you will know. Hello is called with context set to global and in turn world will be called with global context which have variable one with value “one”.

Explicit Binding


We can do explicit binding using the call and apply functions. Both takes the first parameters as the object which you want to be the in the function. They have different behavior with the parameters but they behave similar way with this.
There is another problem which we see is when we lost the context of this in the function. Very common problem is if you are making an Ajax request and in your success method you want to call the function of context in which ajax was made. However, it does not happen. So to make sure you have same context all over the function try to keep an original reference to the this keyword in separate variable.

Var self = this;

As the first statement of the function. This way it will be hard binding and you will always have the reference to the original this.

Or what else we can do? We can use the bind function in ES 5. If you are not using ES 5, than you can go to MDN bind page and check the polyfill for this bind function.

New keyword


What happen when we add a new keyword in front of a function call? When we put a new keyword below are things which happen

  1. A new object is created
  2. A new object is linked
  3. Newly created object will be set as a context of the function.
  4. And the newly created object will be returned if the function otherwise is not returning anything.

So how do we decide which binding is going to take place when we see a piece of code and see that there are multiple things going on here
There is a precedence

  1. If the function is called with new keyword than use the newly created object.
  2. Was there any explicit binding? If yes than use the object passed.
  3. Is there any owning object which called the function? If yes, use that object.
  4. We default to the global object if not in strict mode otherwise to undefined.

Happy Coding!!

No comments:

Post a Comment