Skip to content

Instantly share code, notes, and snippets.

@phund
Last active September 26, 2016 10:01
Show Gist options
  • Save phund/dd9c12e92e7e0462bed2578164cc5c5a to your computer and use it in GitHub Desktop.
Save phund/dd9c12e92e7e0462bed2578164cc5c5a to your computer and use it in GitHub Desktop.
Javascript - Important things that must know

Reference and recommand read from http://speakingjs.com/

Semicolons: Automatic Semicolon Insertion.

Primitive Values Versus Objects

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 and null

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

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';

Scope, Hoisting, Closures

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.

The IIFE Pattern: Introducing a New Scope

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 });
    }());
}

Special Number values

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

Comparing String (case-sensitive)

'B' > 'A' => true
'B' > 'a' => false ???

Function

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 () {
        ...
    };

Environments

http://speakingjs.com/es5/ch16.html#environments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment