Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML5

JavaScript - Foundation of the Language

4.82/5 (24 votes)
6 Aug 2011CPL10 min read 36.5K  
Delve deep into JavaScript Basic/object types, function, execution context, Scope Chain, essence of Closure and anonymous function (lambda)

Introduction

JavaScript "was born under the shadow of Java" - Brenden Eich

It is "the most misunderstood programming language in the world" - Douglas Crockford

JavaScript has been used so widely nowadays, nearly everywhere as long as you are using a web browser and surfing the internet, most of the websites have JS inside, and even server side - nodejs

According to http://langpop.com/, JavaScript is the fourth popular programming language in the world.

In this post, I am trying to use refined language to cover some foundations of JavaScript (many of which have confused quite a number of developers) including basic data types, comparison mechanism, functions, execution context, Variable Scope Chain, essence of Closure and anonymous function (lambda). Hope it can more or less help people have more fun and less frustration in the future JS coding.

Basic Data Types/Object Types

In JavaScript, there are 5 basic types: Undefined, Null, Boolean, Number and String, integers boolean values and strings are accessed by value, that's different with many modern languages like C# (System.String) or Python (PyStringObject), strings are objects and passed by reference. The JS code snippet below proves that string is stored in the stack and passed by value.

JavaScript
var str = "a";
                
function strValTest(s) {
    s = "b";  // "s" is a String value: "a".
    alert(s); // Will alert "b".
}
strValTest(str);
alert(str); 	// Will alert "a", because when called strValTest, 
		// String variable's value is passed as argument.

String in JavaScript is also immutable just like many other languages, i.e., any change applied on an existing string will create a new string in memory and destroy the old one (this is still different from C# in which there is a String Intern Pool to store all String values in managed heap). The code snippet below shows the difference between string and String:

JavaScript
var str1 = "A new String";
console.log("str1");
console.log(str1 instanceof String); 	// false
console.log(str1 instanceof Object); 	// false
console.log(typeof (str1)); 		// string

var str2 = new String("A new String");  	// Create a new Object stored 
					// on the heap with value "A new String"
console.log("str2");
console.log(str2 instanceof String); 	// true
console.log(str2 instanceof Object); 	// true
console.log(typeof (str2)); 		// object

Then you might have the question: how come string instance has methods now that string is value type? The answer is that in JavaScript there are corresponding Object wrappers for the basic types: Number, Boolean and String, they inherit from Object and have their own properties and methods such as Number.toFixed() and String.indexOf(). A simple code snippet has been given below:

JavaScript
string str = "I am a JSer"; 	// Create a new string variable on the stack 
				// with value "I am a JSer".
alert(str.indexOf("JSer"));

Essentially at the back end, JS interpreter will temporarily creates a new String object and invokes its instance method "indexOf", after the method call finished, the temporary String object will be claimed, the process can be demonstrated as below:

JavaScript
string str = "I am a JSer";
var tmp = new String(str);
alert(tmp.indexOf("JSer"));
tmp = null;

Comparison

Comparison might be a very confused part in JavaScript, why? See the code below:

JavaScript
console.log(null == undefined); 	// true Per ECMA-262, null and undefined are 
				// superficially equal, essentially "the value 
				// undefined is a derivative of 
				// null"<professional>.
console.log(null === undefined); 	// false
console.log(NaN == NaN);  		// false. A specific NaN is not considered 
				// equal to another NaN because they may be 
				// different values. Also refer: 
				// http://en.wikipedia.org/wiki/NaN
console.log('5' == 5);   		// true. 
console.log('5' === 5);   		// false. typeof('5') is string and 
				// typeof(5) is number
console.log(false == 0);  		// true
console.log(true == 1);  		// true
console.log(null == 0);  		// false

console.log(typeof (null)); 	// object
console.log(typeof (undefined)); 	// undefined

Foo.prototype = {
	constructor: Foo,
	valueOf: function () {
		return "Object Foo";
	},
	toString: function () {
		return "Foo";
	}
};

var foo1 = new Foo();
console.log("foo1 == foo2: " + (foo1 == "Object Foo")); 	// true will call 
							// foo1.valueOf() 

var foo2 = new Foo();
console.log("foo1 == foo2: " + (foo1 == foo2)); 	// false foo1, foo2 points to 
						// different instance of Foo

foo2 = foo1;
console.log("foo1 == foo2: " + (foo1 == foo2)); // true no doubt
</professional>

Are you sweating? I did... So I read books and copied the paragraph below from <Professional JavaScript for Web Developers>.

  • If an operand is a Boolean value, convert it into a numeric value before checking for equality.
  • A value of false converts to 0, whereas a value of true converts to 1.
  • If one operand is a string and the other is a number, attempt to convert the string into a number before checking for equality.
  • If either operand is an object, the valueOf() method is called to retrieve a primitive value to compare according to the previous rules. If valueOf() is not available, then toString() is called.
  • The operators also follow these rules when making comparisons:
  • Values of null and undefined are equal.
  • Values of null and undefined cannot be converted into any other values for equality checking.
  • If either operand is NaN, the equal operator returns false and the not - equal operator returns true. Important note: Even if both operands are NaN , the equal operator returns false because, by rule, NaN is not equal to NaN.
  • If both operands are objects, then they are compared to see if they are the same object. If both operands point to the same object, then the equal operator returns true . Otherwise, the two are not equal.

Function

In JavaScript, function is not only a traditional function but also an object, defining a function is actually defining a pointer to that function, and function is not only a traditional function but also an Object. I wrote the code snippet below for better understanding:

JavaScript
function dummyFunc() { 	// Define a function and a pointer to it, 
			// the pointer's name is "dummyFunc"
	this.DummyProperty = "Dummy Property";
	console.log("Dummy func");
}

var tempFunc = dummyFunc; 	// Define a variable tempFunc, 
			// let it equal to dummyFunc which is a function pointer 
			// pointing to function defined above
dummyFunc = null; 		// null the dummyFunc
tempFunc(); 		// tempFunc still points to the function defined above 
			// so still can be executed.

var dummy = new tempFunc(); // Will invoke tempFunc's constructor to form a new Object
console.log(dummy.DummyProperty);

Another very important point of functions is the parameters, in JavaScript, function's arguments are ALL passed by value, NOT reference even if the argument is an Object, to prove this please see the code snippet below:

JavaScript
var person = new Object();
function setName(obj) {
	obj.Name = "Wayne"; // obj is actually newly created and given the pointer's 
			// value, so obj and the reference type outside this 
			// function will both point to the Object on the heap, 
			// thus operation on obj will affect the Object passed 
			// in the function.
	
	obj = new Object(); // By executing this line, 
			// temporary variable obj will point to a new Object, 
			// has no relationship with the passed-in Object any more.
	obj.Name = "Wendy";
}

setName(person); 		// Executing this line will pass person's pointer stored 
			// in stack to the function setName, 
alert(person.Name); 	// Will alert "Wayne"

Execution Context and Variable Scope Chain

Execution context is an environment in which all JavaScript runs, if not specified, the context is usually global (window), or can be specified by invoking call/apply. In a lower level, when JavaScript interpreter starts executing a function, this function's execution context will be pushed into stack, then the function itself will be pushed into stack.

Code snippet picked from: http://www.nczonline.net/blog/2010/02/16/my-javascript-quiz/.

JavaScript
var x = 5,
o = {
	x: 10,
	doIt: function doIt() {
		var x = 20;
		setTimeout(function () {
			alert(this.x);
		}, 10);
	}
};
o.doIt(); // Will alert 5 because the execution context is window, window.x = 5;

o.doIt = function () {
	var x = 20;
	// Change the function's execution context by call()/apply 
	setTimeout((function () { alert(this.x); }).apply(o), 20);
}
o.doIt(); // Will alert 10 because execution context is object o, o.x = 10;

A scope chain is a list of objects that are searched for identifiers appear in the code of the context. When a snippet of code is executing under its execution context, within the context a Scope Chain is formed with local variables at beginning and global variables at ending, JavaScript resolves identifiers within a particular context by climbing up the scope chain, moving locally to globally, if a variable cannot be found after traversing the whole Scope Chains, an error will occur. Inside a function, the very first variable in its Scope Chain is arguments.

execution-context.png

JavaScript
var name = "solarSystem"; 	// Assuming the global execution context is 
			// The Universe here:)
        
function earth() {
	var name = 'earth';
	(function () {
		var name = 'country'; // name belongs to local Scope Chain now
		alert(name); // country
	})();
	alert(name); // earth
}
earth(); // In the earth execution context, 
	// "The Universe"'s Scope Chain contains solarSystem can be accessed.

alert(name); 	// solarSystem
alert(blah); 	// Throw error, because cannot find variable definition 
		// for "blah" after traversing the entire Scope Chain.

Closure

Douglas Crockford: "JavaScript has closures. What this means is that an inner function always has access to the vars and parameters of its outer function, even after the outer function has returned. This is an extremely powerful property of the language."

In JavaScript, a closure is formed when you nest functions, inner functions can refer to the variables present in their outer enclosing functions even after their parent functions have already executed.

Let's first take a look at a basic Closure:

JavaScript
function foo(x) {
	var y = 2;

	return function (z) {
	console.log("x + y + z: " + (x + y + z));// Result will be 1 + 2 + 3 = 6 
	}
}
var bar = foo(1); // Bar is now a closure
bar(3);

To deeply understand closure, we must first understand function, Execution Context and Scope Chain I described above, so describe the code snippet above could be: foo is defined as a function pointer, the function takes one parameter, so this parameter belongs to its Scope Chain when it is called in future, inside foo, a local variable y is defined with integer value 2, so it is also in the Scope Chain, and finally it returns an anonymous function which takes one parameter z, once foo is called, it returns a pointer which points to this anonymous function, the entire process can be described in detail below:

  1. Prepare Execution Context for foo.
  2. Scope Chain for foo will be formed, members on the chain: arguments, y, anonymous function.
  3. Anonymous function is defined but not executed, when it is executed in the future, its own Scope Chain will also be formed at the lower level of foo's Scope Chain, members on the Chain: arguments, z, and the most important, foo's Scope Chain will be retained for this anonymous function.
  4. foo returns the anonymous function, a closure will be created, Scope Chains in the Closure will be retained unless program explicitly nulls it. Please note when foo returns, the anonymous function inside it is not executed!
  5. When executing bar passing parameter 3, JavaScript interpreter will firstly search bar's Scope Chain and try to find x, y, z in, z is 3 but cannot find x and y, then it climbs up one level, and finds retained Scope, x's value is 1, and y's value is 2 (if not found it will climb up again, in this case, it will be global), ah-ha, we found all of them, result is 6.

Clear? Not confused? I hope you are:) Simply saying, a Closure is a function that can access parent Scope Chain AND the Scope Chain is retained!

The code snippet below should help us to completely understand "retained Scope Chain":

JavaScript
function wayneClosore() {
	var i = 0;
	i++;
	return function () {
		console.log(i);
	};
}

var closure = wayneClosore();
closure(); // 1
closure(); // 1
closure(); // 1
closure(); // 1

As soon as we create the new Closure - "closure", its outer function's Scope Chain is retained for it (i.e. variable "i" is stored in the Scope Chain with value 1), so later on when this closure is executed, it will fetches the stored Scope Chian in which the variable "i" was 1, no matter how many times it executes, what the code above actually does is simply print out i whose value is 1, result will always be 1.

So now that Scope Chain was retained, variables inside it could be changed, if I modify the above code as below:

JavaScript
function wayneClosore() {
	var i = 0;
	return function () {
		console.log(++i);
	};
}

var closure = wayneClosore();
closure(); // 1
closure(); // 2
closure(); // 3
closure(); // 4

Every time I executed "closure", it fetches variable "i" in the Scope Chain and keeps on increasing its value by i each time.

In addition, if there is more than one inner function inside one function body, then the retained Scope Chain will be shared between each other, please refer to one more example below:

JavaScript
function shareScope() {
	var n = 0;

	return {
		"innerFuncA": function () { console.log(++n); },
		"innerFuncB": function () { console.log(++n); }
	};
}

var shareScopeInstance = shareScope();
shareScopeInstance.innerFuncA(); // 1
shareScopeInstance.innerFuncB(); // 2 

Delve deeper, essentially in ECMAScript, functions have an "Internal Property" - [[Scope]], ECMA-262 defines it as: A lexical environment that defines the environment in which a Function object is executed. As an instance, in the example above, when foo was executed and return value to bar, foo's Scope Chain was save into bar's [[Scope]] property.

Let's finally take a look at one example which might confused a lot of people, and then finish the Closure part.

JavaScript
function buildList(list) {
	var result = [];
	for (var i = 0; i < list.length; i++) {
		result.push(function () {
			console.log(++i);
		});
	}
	return result;
}

var fnlist = buildList([1, 2, 3]);
for (var idx in fnlist)
	fnlist[idx]();

In the example above, the answer is NOT "1,2,3", after buildList is executed, result is an array that contains n (n = 3) closures, all of them share the same Scope Chain created by buildList, when each of them is executed, JS interpreter fetches the Scope Chain and looking for i, what is i'value in the Scope Chain? After the for loop i became 3 since JS has no blocked scope i still exists outside of for loop, and in the console you will see "4, 5, 6" printed out.

Anonymous Function (Lambda)

As long as we understand Scope Chain and Closure completely, there will be no confusion about anonymous function, it is essentially a declared function without a function pointer points to it, it is always used to setup a "blocked-scope", for example, many JavaScript libraries were executed inside a big anonymous function:

JavaScript
(function (window, undefined) {
	var VirtualCompany = function () {
		
	};
})(window);

The anonymous function is executed as soon as it is downloaded completely, passing in the window object and only expose one global object: VirtualCompany, so that the library encapsulates its internal implementation and won't conflict with other JS Libs.

By employing anonymous function, we can modify the Closure example I demonstrated above, to let it achieve our original goal:

JavaScript
function buildList(list) {
	var result = [];
	for (var i = 0; i < list.length; i++) {
		result.push((function (i) {
			return function () { console.log(++i); };
		})(i));
	}
	return result;
}

var fnlist = buildList([1, 2, 3]);
for (var idx in fnlist)
	fnlist[idx]();

This time, the result will be "1,2,3", because every time's invocation on "result.push", what was pushed into the array? The answer is: A closure with the anonymous function's Scope Chain stored, what's inside the anonymous function's Scope Chain? i in the for loop. During each iteration inside the for loop, an anonymous function is executed by passing i into it, so i exists in its Scope Chain, and since the anonymous function returns another anonymous function, a Closure was formed and the Scope was retained.

Summary

JavaScript is a great language and it has a very bright future in my humble opinion, considering its important role in the coming Web Standard - HTML5, event I/O based, high performance web server - nodejs, and JavaScript will also play an important role in the coming Cloud time, it is a time for the developers who didn't seriously learn it before to re-learn it. In fact, I have written broken JavaScript code for 6 years, however, to be honest, I am ashamed that I never seriously learnt it in the past, some of its basic theory, useful skills as well as best practices I never knew, so I wrote this post to summarize things I re-learnt. Hope it will help programmers like me.

Happy JavaScript coding! Be a happy JSer. :)

Further Reading (Strongly Recommended)

License

This article, along with any associated source code and files, is licensed under The Common Public License Version 1.0 (CPL)