Hey, I'm writing a book too :) Click the link below to preorder and save ;)
»» Get the Only Reference You'll "ever" Need on JavaScript Engineering Interviews, Now! ««
April 22nd in Basics, Tutorial by .

Variables, Scopes, and Hoisting in JavaScript

JavaScript Hoisting

Variable Types in JavaScript

Everything is an object in JavaScript. And those objects can have various types.

JavaScript supports six different types of variable.

Let us look at each of these types in detail:

boolean
sample values:(true, false)
The boolean variable is used to record a value of either true or false. Internally this is essentially stored as 1 for true and 0 for false.
number
sample values:(1, -24, 0.012)
The number variable holds any type of number, either an integer or a real number.
string
sample values:(“Hello universe!”)
The string variable type stores a string of characters, typically making up either a word or sentence. string variables can also be assigned empty strings.
function
sample values:any builtin or user-defined function
A function is one of the basic building blocks of most programming languages including JavaScript. Functions provide a way to organize functionality into clean, reusable modules that can be accessed from any other JavaScript to perform specific tasks
object
sample values:({}, document, window)
JavaScript provides a set of predefined objects to which the JavaScript programmer has access.
undefined
sample values:(undefined)
undefined is an special object of type “undefined”. We’ll be having more fun with undefined and null datatypes in the upcoming tutorials :)

You can click here, to get the source code of this tutorial (5Kb zipped archive) »»

To get the type of a certain variable, you can use the typeof operator.

var test = 12;
console.log(typeof test);
//will log "number"

Variable Scopes in JavaScript

JavaScript, unlike in other programming languages, only restricts the scope of variable to the block that they are defined in, if that block is a function(). So, variables defined inside for loops, or if statements are also available after their definition.

Before starting, let us create some namespaces and functions:

//define an o2 namespace if it does not exist.
if(!o2){var o2 = {};}

//define a tutorial namespace if it does not exist.
if(o2 && !o2.tutorial){ o2.tutorial = {}; }

//if our tutorial is already defined, exit immediately.
if(o2.tutorial.scope){ throw 'Trying to override an existing "o2.tutorial.scope" namespace'; }

//tutorial
o2.tutorial.scope = {
	demo: function(){
		/* out tutorial will go here. */
	}
};

At each tutorial, I will follow a similar approach:

  • Create a o2.tutorial.{lesson-name} namespace,
  • and do all my experiments inside the demo functions

There may be exceptions to this, of course. It may be technically impossible to do so, in some cases.
But this will be the approach I will follow 99% of the time.

We will use o2.Debugger object, that we’ve created in the former tutorial.

Here is the complete source code with explanatory comments:

//define an o2 namespace if it does not exist.
if(!o2){var o2 = {};}
//define a tutorial namespace if it does not exist.
if(o2 && !o2.tutorial){ o2.tutorial = {}; }
//if our tutorial is already defined, exit immediately.
if(o2.tutorial.scope){ throw 'Trying to override an existing "o2.tutorial.scope" namespace'; }

//tutorial
o2.tutorial.scope = {
	init:function(){
		var logger = o2.Debugger;
		logger.init(document.getElementById('Output'));			
	},
	demo: function(){	
		var out = o2.Debugger.println;
		
		//Define an outer variable.
		var outerVariable = 10;
		
		//You can access the outer variable after it is defined.
		out('outerVariable:'+outerVariable);
		
		function testMethod(){
			//Define an inner variable.
			var innerVariable = 11;
			
			out('innerVariable:'+innerVariable);
			
			for(var index=0;index<10;index++){
				out('index:'+index);
			}
			
			//Note that index is accessible outside the for loop.
			//this scoping issue is different than the block-level
			//scope in other languages like Java, C++, or C#
			out('index(outside for):'+index);

			//testMethod "closes over" outerVariable, you can access it.
			out('outer var (in testMethod):'+outerVariable);
		}
		
		//inner variable is not accessible here
		out('is innerVariable accessible outside testMethod:' + (typeof innerVariable != 'undefined'));
		
		function testMethod2(){
			out('in test method2');
			//outer variable is accessible here.
			out('test method 2 (outerVariable):' + outerVariable);
		}
		
		//you can access these functions.
		testMethod();
		testMethod2();
	},
	demoHoisting: function(){
		var out = o2.Debugger.println;
		
		out('Hoisting demo:');
		
		out('test variant: ' + testVariant);
		out('test method: ' + testMethod);
		out('calling test method');
		testMethod();
		
		var testVariant = 10;
		
		function testMethod(){
			out('hello world');			
		}
	}
};

And the page that calls the demo methods:

<html>
<head>
</head>
<body>
<script type="text/javascript" src="js/o2.debugger.js"></script>
<script type="text/javascript" src="js/o2.tutorial.scope.js"></script>
<script type="text/javascript">
	window.onload = function(){
		var tutorial = o2.tutorial.scope;
		tutorial.init();
		tutorial.demo();
		tutorial.demoHoisting();
	};
</script>
<div id="Output">
</div>
</body>
</html>

tutorial.init() will simply initialize the o2.Debugger to spit out strings to an output div in the page.

Here’s the result of the tutorial.demo() function:

outerVariable:10
is innerVariable accessible outside testMethod:false
innerVariable:11
index:0
index:1
...
index:9
index(outside for):10
outer var (in testMethod):10
in test method2
test method 2 (outerVariable):10

Note that the loop variable index in the for loop, is accessible outside the for loop.
this scoping issue is different than the block-level scope in other languages like Java, C++, or C#.

Wait… What? Hoisting?

Another interesing variable scope issue in JavaScript is hoisting.

The variable declerations will be internally moved (hoisted) to the top of the enclosing function. Inner functions will be completely hoisted along with the entire function body.

So the demoHoisting method will be interpreted by the JavaScript engine like:

demoHoisting: function(){
	//decleration is hoisted.
	var testVariant;

	//entire function body is hoisted.
	function testMethod(){
		out('hello world');			
	}		
		
	var out = o2.Debugger.println;
	
	out('Hoisting demo:');
	
	out('test variant: ' + testVariant);
	out('test method: ' + testMethod);
	out('calling test method');
	testMethod();
	
	testVariant = 10;
}

So the output of the hoisting section will be as follows:

Hoisting demo:
test variant: undefined
test method: function testMethod() { out("hello world"); }
calling test method
hello world

Samurai Tip
It’s a good practice to declare all the variables and closures at the top, before using them to avoid nasty side effects ;)

That’s what Douglas Crockford suggests in his book “JavaScript the good Parts” as well.

Strange language, JavaScript is.
– Yoda

You see, even the most basic concepts in JavaScript require some serious thought.

Isn’t it ;) ?

It's me: Volkan! Jack of all Trades, Samurai of JavaScript ;) Since 2003, I’ve been doing front-end development on client-heavy AJAX web applications. Currently, I'm a JavaScript Hacker at "SocialWire". Before that I was a VP of Technology at "GROU.PS", a well-known do-it-yourself social networking platform that allows people to come together and form interactive communities around a shared interest or affiliation. Before that, I was a JavaScript Engineer at "LiveGO", a globally known social mash-up. Before that, I was the CTO of a business network ("cember.net") which was acquired by Xing AG for around 4.2M Euros. See my linkedin profile to find more about me; I also share worth-following bits an pieces on twitter.

VIsit Volkan Özçelik's website

2 Comments

Leave a Reply





o2.js _
Fork Ribbon