Reference and recommand read from http://speakingjs.com/
JavaScript has only six types
Undefined, Null
Boolean, String, Number, and
Object
JavaScript makes a somewhat arbitrary distinction between values:
The primitive values are booleans, numbers, strings, null, and undefined.
All other values are objects.
A major difference between the two is how they are compared;
Each object has a unique identity and is only (strictly) equal to itself
In contrast, all primitive values encoding the same value are considered the same
undefined means “no value.”
Uninitialized variables are undefined
> var foo;
> foo
undefined
Missing parameters are undefined:
> function f(x) { return x }
> f()
undefined
If you read a nonexistent property, you get undefined:
> var obj = {}; // empty object
> obj.foo
undefined
null means “no object.” It is used as a nonvalue whenever an object is expected (parameters, last in a chain of objects, etc.).
if (x === undefined || x === null) {
...
}
if (!x) { //both undefined and null are considered false. (false, 0, NaN, and '' are also considered false)
...
}
Strict mode (see Strict Mode) enables more warnings and makes JavaScript a cleaner language (nonstrict mode is sometimes called “sloppy mode”). To switch it on, type the following line first in a JavaScript file or a <script> tag:
'use strict';
The scope of a variable is always the complete function (as opposed to the current block). For example:
function foo() {
var x = -512;
if (x < 0) { // (1)
var tmp = -x;
...
}
console.log(tmp); // 512
}
We can see that the variable tmp is not restricted to the block starting in line (1); it exists until the end of the function
Each variable declaration is hoisted: the declaration is moved to the beginning of the function, but assignments that it makes stay put. As an example, consider the variable declaration in line (1) in the following function:
function foo() {
console.log(tmp); // undefined
if (false) {
var tmp = 3; // (1)
}
}
Internally, the preceding function is executed like this:
function foo() {
var tmp; // hoisted declaration
console.log(tmp);
if (false) {
tmp = 3; // assignment stays put
}
}
Each function stays connected to the variables of the functions that surround it, even after it leaves the scope in which it was created. For example:
function createIncrementor(start) {
return function () { // (1)
start++;
return start;
}
}
The function starting in line (1) leaves the context in which it was created, but stays connected to a live version of start:
> var inc = createIncrementor(5);
> inc()
6
> inc()
7
> inc()
8
A closure is a function plus the connection to the variables of its surrounding scopes. Thus, what createIncrementor() returns is a closure.
Sometimes you want to introduce a new variable scope—for example, to prevent a variable from becoming global. In JavaScript, you can’t use a block to do so; you must use a function. But there is a pattern for using a function in a block-like manner. It is called IIFE (immediately invoked function expression, pronounced “iffy”):
(function () { // open IIFE
var tmp = ...; // not a global variable
}()); // close IIFE
Be sure to type the preceding example exactly as shown (apart from the comments). An IIFE is a function expression that is called immediately after you define it. Inside the function, a new scope exists, preventing tmp from becoming global. Consult Introducing a New Scope via an IIFE for details on IIFEs.
IIFE use case: inadvertent sharing via closures
Closures keep their connections to outer variables, which is sometimes not what you want:
var result = [];
for (var i=0; i < 5; i++) {
result.push(function () { return i }); // (1)
}
console.log(result[1]()); // 5 (not 1)
console.log(result[3]()); // 5 (not 3)
The value returned in line (1) is always the current value of i, not the value it had when the function was created. After the loop is finished, i has the value 5, which is why all functions in the array return that value. If you want the function in line (1) to receive a snapshot of the current value of i, you can use an IIFE:
for (var i=0; i < 5; i++) {
(function () {
var i2 = i; // copy current i
result.push(function () { return i2 });
}());
}
NaN
typeof NaN => 'number'
Check NaN???
NaN == NaN ?? => false
isNaN(NaN) => true
isNaN('xyz') => true
typeof(value) === 'number' && isNaN(value) => ...
Infinity/-Infinity (100/0)
Infinity - Infinity = NaN
Infinity / Infinity = NaN
Infinity + Infinity = Infinity
Infinity * Infinity = Infinity
var x = Infinity;
x === Infinity => true
isFinite(5) => true
isFinite(Infinity) => false
isFinite(NaN) => false
Two Zeros
-0
+0
'B' > 'A' => true
'B' > 'a' => false ???
Via a function expression
var add = function (x, y) { return x + y };
=> Because normal function expressions don’t have a name, they are also called anonymous function expressions.
The name of a named function expression is only accessible inside the function expression
var repeat = function me(n, str) {
return n > 0 ? str + me(n-1, str) : '';
};
console.log(repeat(3, 'Yeah')); // YeahYeahYeah
console.log(me); // ReferenceError: me is not defined
Via a function declaration:
function add(x, y) {
return x + y;
}
The preceding looks like a function expression, but it is a statement. It is roughly equivalent to the following code:
var add = function (x, y) {
return x + y;
};
In other words, a function declaration declares a new variable, creates a function object, and assigns it to the variable.
Via the constructor Function()
The constructor Function() evaluates JavaScript code stored in strings. For example, the following code is equivalent to the previous example:
var add = new Function('x', 'y', 'return x + y');
However, this way of defining a function is slow and keeps code in strings (inaccessible to tools). Therefore, it is much better to use a function expression or a function declaration if possible. Evaluating Code Using new Function() explains Function() in more detail; it works similarly to eval().
Hoisting
Hoisting means “moving to the beginning of a scope.” Function declarations are hoisted completely, variable declarations only partially.
Function declarations are completely hoisted. That allows you to call a function before it has been declared:
foo();
function foo() { // this function is hoisted
...
}
The reason the preceding code works is that JavaScript engines move the declaration of foo to the beginning of the scope. They execute the code as if it looked like this:
function foo() {
...
}
foo();
var declarations are hoisted, too, but only the declarations, not assignments made with them. Therefore, using a var declaration and a function expression similarly to the previous example results in an error:
foo(); // TypeError: undefined is not a function
var foo = function () {
...
};
Only the variable declaration is hoisted. The engine executes the preceding code as:
var foo;
foo(); // TypeError: undefined is not a function
foo = function () {
...
};
http://speakingjs.com/es5/ch16.html#environments