Introduction

JavaScript "was born under the shadow of Java" - Brenden Eich, it is "the most misunderstood programming language in the world" - Douglas Crockford. JavaScript was 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 foundation of JavaScript (many of which confused quite a number of developers) including basic data types, comparison mechanism, functions, Execution context, Variable Scope Chain, essence of Closure and anounymous 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), string are object and passed by reference, JS code snipppet below proves that string is stored in the stack and passed by value. 
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 is 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 (there is still different with C# in which there is a String Intern Pool to store all String values in managed heap). Code snippet below shows the difference between string and String: 

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 question of: how come string instance has methods now that string is value type? The answer is that In JavaScript there are corresponding Object wrapper 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(), simple code snippet below:

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:

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 code below:

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 point to diffrent instance of Foo

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

Are you sweating? I did... So I read book and copied 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 traditional function but also an object, define a function is actually define a pointer to that function, and function is not only traditional function but also an  Object. I wrote code snippet below for better understanding: 

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 code snippet below:

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 a 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/ 

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 find 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 

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: 

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 details 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 null 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 clime up one level, and found retained Scope, x's value is 1, and y's value is 2 (if not found it will clime up again, in this case, it will be global), ah-ha, we found all of them, result is 6.  

Clear? No confuse? I hope you are:)  Simply saying, a Closure is a function can access parent Scope Chain AND the Scope Chain is retained

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

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 executes how many times, 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:

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 keep on increasing its value by i each time.  

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

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 people, and then finish Closure part. 

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 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 library was executed inside a big anonymous function:

(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 be 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: 

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 existing in its Scope Chain, and since the anonymous function return 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 humbly 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 time for the developers who didn't seriously learnt it before to re-learn it. In fact I have brokenly wrote 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) 

Professional JavaScript for Web Developers (Wrox Programmer to Programmer) 

JavaScript. The core 

Scope In JavaScript 

ECMA-262 

New JavaScript Engine Module Owner 

Douglas Crockford's Wrrrld Wide Web 

John Resig - JavaScript Programmer 

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"