Preface
First, a big thanks to all of you for supporting my last series,
Introduction
I enjoyed the interaction with all of you -- reading your comments, questions, and messages. I feel excited and I am starting a new series called “Inquisitive Developer – JavaScript”. This new series will go in-depth about JavaScript programming language. I will try my best to take you on this programming journey and cover common mistakes, misconceptions, and cool features of the King of scripts, JavaScript.
I welcome you all to the new series!
Getting started
Let me start with a basic keyword ‘var’.
> var variableName = ‘assignment value’;
There are two parts here, i.e. declaration and initialization. I will split them as:
> var variableName; // Code 1> var variableName = ‘assignment value’; // Code 2
Code 1 will declare variable only and the default value assigned is ‘undefined’. JavaScript assigns undefined value, as the purpose is to assign default value to this variable. The benefit of undefined is that a developer may not know the value of the variable during declaration.
Code 2 JavaScript interpreter interprets it as declared and initialized together,
> var variableName;
> variableName = ‘assignment value’;
To understand ‘hoisting’ we will first learn scoping.
Scoping
JavaScript follows lexical scoping (static scoping). Lexical means vocabulary of a language. Scoping means the scope of a variable. There are two types of variable scopes global and local.
Global scope
A variable that is declared outside the function. This variable can be accessible throughout the program, for example,
- var x = 90;
- function f1() {
- console.log(x);
- };
- f1();
In above example x is created in global scope and is accessible by f1()
Any variable created in global scope is added to global-context window object. You can check as,
- var x = 90;
- function f1() {
- console.log(x);
- };
- f1();
- console.log(window.x);
Now I can remove ‘var’ and create x variable.
Question: Will it work and give the same output?
Ans: Yes, it works well because we are operating at non-strict mode currently. It is recommended to use “use strict” mode, but currently, I am not bothered about it.
- x = 90;
- function f1() {
- console.log(x);
- };
- f1();
Local scope (Function-level scope)
A variable that is declared inside the function. Seems straightforward, here is the demonstration,
- function f1() {
- var x = 1;
- console.log(x);
- } f1();
Let us try to use block scope which we generally use in other programming languages like C, C++, C#,
- function f1() {
- var x = 1;
- console.log(x);
- if (true) {
- var x = 2;
- console.log(x);
- }
- console.log(x);
- };
- f1();
Above we declared x again inside if condition. In C or other programming languages, there is a block scope (curly braces) so outside if x value should remain 1 it will print 2.
No block-level scope
In JavaScript, there is no block scope and it is local scope within function. Function creates scope in JavaScript. Makes it trickier,
- function f1() {
- var x = 1;
- console.log(x);
- function f2() {
- if (true) {
- var x = 2;
- console.log(x);
- }
- };
- f2();
- console.log(x);
- };
- f1();
We created another function called f2() within f1(), therefore a new function scope is created.
A misconception
One of the most popular codes which all of us have written in our learning development is FOR loop.
- for (var index = 0; index < 5; index++)
- {
- console.log(index);
- }
We think that the scope of index variable is just limited to FOR loop but it is incorrect. Here is a program,
- console.log(index);
- for (var index = 0; index < 5; index++)
- {
- console.log(index);
- }
- console.log(index);
The first line prints undefined because of a concept variable “hoisting”. I will talk about it shortly. The last line prints 5 because the index is not only restricted to FOR but because there is block-level scoping in JavaScript. Therefore, the index is accessible throughout the scope.
There is a concept in JavaScript called “Hoisting” which we will review.
Priority
The local variable gets priority over global variable. If you declare a variable with the same name in the below example, which is using anonymous function via arrow ECMAScript 6, the variable index is created inside an anonymous and outside anonymous function. The output will depend upon the scope of the variable,
- var index = 9;
- (() =>
- {
- for (var index = 0; index < 5; index++)
- {
- console.log(index);
- }
- })();
- console.log(index);
Variable Hoisting
JavaScript variables are ‘hoisted’. This means the variables will be hoisted at the top regardless of its placement. Hoist means to raise or lift up. Similarly, variables are hoisted on top but not on assignment or initialization. A small code shows that,
- console.log(hoist1);
- var hoist1 = 'hoisting';
- console.log(hoist1);
The above is read by JavaScript interpreter in different ways because hoisting is done and variables are hoisted at top.
- var hoist1;
- console.log(hoist1);
- hoist1 = 'hoisting';
- console.log(hoist1);
Hoisting precedence
An interesting fact about precedence when there exists a variable with the same name and function is that function takes precedence over the variable declaration. But if variable initialization is done then it’s of a higher order. Example,
- var f1;
- function f1(params) {
- console.log('its function1');
- };
- console.log(typeof f1);
- var f2 = 'its variable';
- function f2(params) {
- console.log('its function2');
- };
- console.log(typeof f2);
Rules of variable definition
- Never create undeclared variables, because these are created as global.
- Undeclared variables unless assigned value give an error if they are referenced, example-
> console.log (a);
The reason is all declared variables are hoisted on top,
- Undeclared variables can be deleted:
Sample one
- a = 10;
- console.log(a);
- delete a;
- console.log(typeof a);
- console.log(a);
Sample two
- var a = 10;
- console.log(a);
- delete a;
- console.log(typeof a);
- console.log(a);
Hoisting functions and expression
We learned earlier in the voice of a developer series that function is also hoisted,
The function expression is not hoisted, please refer to code below,
- fncHoisted();
- fncNotHoisted();
- function fncHoisted() {
- console.log("Definition hoisted!");
- }
- var fncNotHoisted = function()
- {
- console.log("Definition not hoisted!");
- };
Block-level scope
So far we have learned that var doesn’t have block scope. But ECMAScript 6 which has let the keyword provide block scope.
Scoping rules
- Unlike var keyword, let provides block and sub-blocks scope. It is similar to other programming languages.
- function f1()
- {
- let name = 'Sumit';
- if (true) {
- let name = 'Jolly';
- }
- console.log(name);
- }
- f1();
- Unlike var, let the keyword does not create a property in a global object, i.e., window.
- var x = 'associate with window object.';
- let y = 'no association.';
- console.log(window.x);
- console.log(window.y);
Output
- Duplicate variables are not allowed,
- var y = 10;
- var y = 20;
- let x = 10;
- let x = 20;
- Always good to declare the variable using let before referencing it, here you can see the difference:
Using let
It will give reference error,
- function do() {
- console.log(foo);
- let foo = 2;
- }
- do();
Using var
It will print undefined rather than error,
- function do()
- {
- console.log(foo);
- var foo = 2;
- }
- do();
Summary
I hope you enjoyed reading this article. Please share your comments/feedback.