All notes
Javascrip

Intro

Good references

Reference.

Datatypes

Types

w3schools: js_datatypes.


// Dynamic datatypes:
var x;               // Now x is undefined
var x = 5;           // Now x is a Number
var x = "John";      // Now x is a String

// Booleans.
var x = true;
var y = false;
// false, 0, empty strings (""), NaN, null, and undefined all become false. All other values become true.
Boolean("");  // false
Boolean(234); // true

// Arrays.
var cars = ["Saab", "Volvo", "BMW"];

// Objects.
var person = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"};

// Undefined and NULL.
var cars;              // Value is undefined
var person = null;     // Value is null

// Typeof
typeof "John"                 // Returns string 
typeof 3.14                   // Returns number
typeof false                  // Returns boolean
typeof [1,2,3,4]              // Returns object
typeof {name:'John', age:34}  // Returns object

// New creates an object.
// Avoid String, Number, and Boolean objects. They complicate your code and slow down execution speed. See below.
var x = new String();          // Declares x as a String object
var y = new Number();          // Declares y as a Number object
var z = new Boolean();         // Declares z as a Boolean object

// The only advantage a String object has over a primitive string value is that as an object it can store properties:
var str = "foo";
str.prop = "bar";
alert(str.prop); // undefined
str = new String("foo");
str.prop = "bar";
alert(str.prop); // "bar"

var str = new String("foo");
typeof str == "string" // false
str instanceof String // true
typeof str.substring == "function" // true
// Now make str a native string:
str = "" + str;
typeof str == "string" // true
str instanceof String // false
typeof str.substring == "function" // true

Numbers


var x1 = 34.00;   // Written with decimals
var x2 = 34;      // Written without decimals

// Extra large or extra small numbers can be written with scientific (exponential) notation:
var y = 123e5;       // 12300000
var z = 123e-5;      // 0.00123

0.1 + 0.2 == 0.30000000000000004
// true
1 + 2 == 3.0000000000000000004
// true
// Numbers in JavaScript are "double-precision 64-bit format IEEE 754 values".

// Parse string as binary
parseInt("011", 2); // 3
parseInt("011", 10); // 11

// Use the unary + operator to convert values to numbers:
+ "42";   // 42
+ "010";  // 10
+ "0x10"; // 16

parseInt("hello", 10); // NaN. Not a number.
1 / 0; //  Infinity.
-1 / 0; // -Infinity.
isFinite(1/0); // false
isFinite(-Infinity); // false
isFinite(NaN); // false

// Math is also a built-in object.
Math.sin(3.5); // -0.35078322768961984
Math.PI; // 3.141592653589793
var circumference = Math.PI * (r + r);

Math


Math.ceil(1.4)
// 2

Strings

Strings in JavaScript are sequences of Unicode characters (UTF-16).


// Strings.
var answer = "It's alright";             // Single quote inside double quotes
var answer = "He is called 'Johnny'";    // Single quotes inside double quotes
var answer = 'He is called "Johnny"';    // Double quotes inside single quotes

"hello".length; // 5
"hello".charAt(0); // "h"
"hello, world".replace("hello", "goodbye"); // "goodbye, world"
"hello".toUpperCase(); // "HELLO"

"hello" + " world"; // "hello world"

"3" + 4 + 5;  // "345"
 3 + 4  + "5"; // "75"

Replace

MDN: replace.


function replacer(match, p1, p2, p3, offset, string) {
  // p1 is nondigits, p2 digits, and p3 non-alphanumerics
  return [p1, p2, p3].join(' - ');
}
var newString = 'abc12345#$*%'.replace(/([^\d]*)(\d*)([^\w]*)/, replacer);
console.log(newString);
// abc - 12345 - #$*%

var str = 'Twas the night before Xmas...';
var newstr = str.replace(/xmas/i, 'Christmas'); // i: ignore case.
console.log(newstr);  // Twas the night before Christmas...

var re = /apples/gi; // g: global.
var str = 'Apples are round, and apples are juicy.';
var newstr = str.replace(re, 'oranges');
console.log(newstr);  // oranges are round, and oranges are juicy.

// Switching words.
var re = /(\w+)\s(\w+)/;
var str = 'John Smith';
var newstr = str.replace(re, '$2, $1');
console.log(newstr);  // Smith, John

function styleHyphenFormat(propertyName) {
  // inline function:
  function upperToHyphenLower(match) {
    return '-' + match.toLowerCase();
  }
  return propertyName.replace(/[A-Z]/g, upperToHyphenLower);
}
console.log(styleHyphenFormat('borderTop'));
// this returns 'border-top'.

Format

There is no built-in format(). You have to build one yourself.

SO: printf string format.


// First, checks if it isn't implemented yet.
if (!String.prototype.format) {
  String.prototype.format = function() {
    var args = arguments;
    return this.replace(/{(\d+)}/g, function(match, number) { 
      return typeof args[number] != 'undefined'
        ? args[number]
        : match
      ;
    });
  };
}

// "{0} is dead, but {1} is alive! {0} {2}".format("ASP", "ASP.NET")
// outputs
//    ASP is dead, but ASP.NET is alive! ASP {2}

HtmlEntities

css-tricks.


function htmlEntities(str) {
    return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}

Objects

JavaScript objects can be thought of as simple collections of name-value pairs. As such, they are similar to:

Everything in JavaScript is an object. Any JavaScript program naturally involves a great deal of hash table lookups.


// Two ways to create an empty object:
var obj = new Object();
var obj = {};
// The latter is "object literal syntax", and is more convenient. This syntax is also the core of JSON format and should be preferred at all times.

var obj = {
  name: "Carrot",
  "for": "Max",
  details: {
    color: "orange",
    size: 12
  }
}

// Attribute access can be chained together:
obj.details.color; // orange
obj["details"]["size"]; // 12

Creates an object prototype, Person, and instance of that prototype, You:


function Person(name, age) {
  this.name = name;
  this.age = age;
}

// Define an object
var You = new Person("You", 24); 

An object's properties can again be accessed in one of two ways. The second method has the advantage that the name of the property is provided as a string, which means it can be calculated at run-time. However, using this method prevents some JavaScript engine and minifier optimizations being applied. It can also be used to set and get properties with names that are reserved words.


// Method 1
obj.name = "Simon";
var name = obj.name;

// Method 2
obj["name"] = "Simon";
var name = obj["name"];

obj.for = "Simon"; // Syntax error, because 'for' is a reserved word
obj["for"] = "Simon"; // works fine

Arrays

Arrays in JavaScript are actually a special type of object. They work very much like regular objects (numerical properties can naturally be accessed only using [] syntax) but they have one magic property called 'length'.


var a = new Array();
a[0] = "dog";
a[1] = "cat";
a[2] = "hen";
a.length; // 3

// A more convenient notation is to use an array literal:
var a = ["dog", "cat", "hen"];
a.length; // 3

// Note that array.length isn't necessarily the number of items in the array.
var a = ["dog", "cat", "hen"];
a[100] = "fox";
a.length; // 101

// Remember: the length of the array is one more than the highest index.

// Query a non-existent array index, you'll get a value of undefined:
typeof a[90]; // undefined

// "not" recommended:
for (var i = 0; i < a.length; i++) {
  // Do something with a[i]
}
// Another way of iterating over an array that was added with ECMAScript 5 is forEach():
["dog", "cat", "hen"].forEach(function(currentValue, index, array) {
  // Do something with currentValue or array[index]
});

a.push(item);
// Take Array as a stack:
a.pop(); // Removes and returns the last item.
// Take Array as a queue:
a.shift(); // Removes and returns the first item.
a.unshift(item1[, item2[, ...[, itemN]]]); // Prepends items to the start of the array.

// Returns a string with the toString() of each element separated by commas.
a.toString();

['a','b'].toString(); // 'a,b'
['a','b'].join('-'); // 'a-b'
['a','b'].reverse(); // [ 'b', 'a' ]

['a','b'].slice(1,5); // [ 'b' ]
> ['a','b'].slice(0,5); // [ 'a', 'b' ]

Comparison

==	equal to
!=	not equal
===	equal value and equal type
!==	not equal value or not equal type
>	 greater than
>=	 greater than or equal to

&&	and
||	or
!	not


123 == "123"; // true
1 == true; // true
// To avoid type coercion:
123 === "123"; // false
1 === true;    // false

var x = 5;
x == 8;	// false
x == 5;	// true
x != 8; // true

x === "5"; //	false
x === 5; //	true
x !== "5"; //	true
x !== 5; //	false
x > 8; //	false	
x < 8; //	true	
x >= 8; //	false	
x <= 8; //	true

var voteable = (age>=0 && age < 18) ? "Too young":"Old enough";

JSON

StackOverflow. JSON.stringify turns an object in to a JSON text and stores that JSON text in a string.
JSON.parse turns a string of JSON text into an object.

How to prettify JSON


// Use JSON.stringify(jsonObj, null, '\t') to format and indent JSON output.

$("pre#result").html(JSON.stringify(data.book,null,'\t') + "\r\n\r\n" + JSON.stringify(data.author,null,'\t'));

<script src="google-code-prettify/run_prettify.js?autoload=true&amp;skin=sunburst&amp;lang=json"></script>

Stringify

Mozilla Developer: stringify.



//-- Replacer being a function

function replacer(key, value) {
  // Filtering out properties
  if (typeof value === "string") {
    return undefined;
  }
  return value;
}

var foo = {foundation: "Mozilla", model: "box", week: 45, transport: "car", month: 7};
JSON.stringify(foo, replacer);
// '{"week":45,"month":7}'

//-- Replacer being an array

// If replacer is an array, the array's values indicate the names of the properties in the object that should be included in the resulting JSON string.

JSON.stringify(foo, ['week', 'month']);  
// '{"week":45,"month":7}'

Statements

var, let, const

let

Mozilla Developer.

let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.


function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // different variable
    console.log(x);  // 2
  }
  console.log(x);  // 1
}

Use let in for loop:


var list = document.getElementById("list");

for (let i = 1; i <= 5; i++) {
  let item = document.createElement("li");
  item.appendChild(document.createTextNode("Item " + i)); // If "var", i will still be 1-5.

  item.onclick = function (ev) {
    console.log("Item " + i + " is clicked."); // If "var", i will always be 6.
  };
  list.appendChild(item);
}

If you use var here, i in the onclick() function will always be 6.

Create a private interface without using closures:


var SomeConstructor;

{
    let privateScope = {};

    SomeConstructor = function SomeConstructor () {
        this.someProperty = "foo";
        privateScope.hiddenProperty = "bar";
    }

    SomeConstructor.prototype.showPublic = function () {
        console.log(this.someProperty); // foo
    }

    SomeConstructor.prototype.showPrivate = function () {
        console.log(privateScope.hiddenProperty); // bar
    }

}

var myInstance = new SomeConstructor();

myInstance.showPublic();
myInstance.showPrivate();

console.log(privateScope.hiddenProperty); // error

Temporal dead zone

In ECMAScript 2015, let will hoist the variable to the top of the block. However, referencing the variable in the block before the variable declaration results in a ReferenceError. The variable is in a "temporal dead zone" from the start of the block until the declaration is processed.


function do_something() {
  console.log(foo); // ReferenceError
  let foo = 2;
}

const

Mozilla.

The const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable, just that the variable identifier cannot be reassigned. For instance, in case the content is an object, this means the object itself can still be altered.

A common convention is to use all-uppercase letters for const variables.


// define MY_FAV as a constant and give it the value 7
const MY_FAV = 7;

// The following will ALL throw an error:
MY_FAV = 20; // Can't change.
const MY_FAV = 20; // Can't redefine.
// The name MY_FAV is reserved for constant above, so this will also fail
var MY_FAV = 20;
let MY_FAV = 20;

// It's important to note the nature of block scoping
if (MY_FAV === 7) { 
    // this is fine and creates a block scoped MY_FAV variable 
    const MY_FAV = 20;
    // MY_FAV is now 20
    console.log("my favorite number is " + MY_FAV);

    // this gets hoisted into the global context and throws an error
    var MY_FAV = 20;
}

// MY_FAV is still 7
console.log("my favorite number is " + MY_FAV);

// Assigning to A const variable is a syntax error
const A = 1; A = 2;

// throws an error, missing initializer in const declaration
const FOO; 

// const also works on objects
const MY_OBJECT = {"key": "value"};
// Attempting to overwrie the object throws an error
MY_OBJECT = {"OTHER_KEY": "value"};
// However, object keys are not protected, so the following statement is executed without problem
MY_OBJECT.key = "otherValue"; // Use Object.freeze() to make object immutable

// The same applies to arrays
const MY_ARRAY = [];
// It's possible to push items into the array
MY_ARRAY.push("A"); // ["A"]
// However, assigning a new array to the variable throws an error
MY_ARRAY = ["B"]

Function

Ref.

A function is created by an expression that starts with the keyword function.

If no return statement is used (or an empty return with no value), JavaScript returns undefined.

Definition, Declaration

A function definition is just a regular variable definition where the value given to the variable happens to be a function.


// This is a function definition.
var square = function(x) {
	return x * x;
};

console.log(square(12));
// 144

// This is a function declaration.
function square(x) {
  return x * x;
}
// Function declaration does not need trailing ';'.

This code works, even though the function is defined below the code that uses it.

This is because function declarations are not part of the regular top-to-bottom flow of control. They are conceptually moved to the top of their scope and can be used by all the code in that scope.


console.log("The future says:", future());

function future() {
  return "We STILL have no flying cars.";
}

Put such a function definition inside a conditional (if) block or a loop is forbidden by the latest standard.


function example() {
  function a() {} // Okay
  if (something) {
    function b() {} // Danger!
  }
}

Storing this stack requires space in the computer's memory. The following code will blow the stack.


function chicken() {
  return egg();
}
function egg() {
  return chicken();
}
console.log(chicken() + " came first.");

Variable scope

Variables declared outside of any function are called global, because they are visible throughout the program.

An important difference between JavaScript and other languages like Java is that in JavaScript, blocks do not have scope; only functions have scope. So if a variable is defined using var in a compound statement (for example inside an if control structure), it will be visible to the entire function. However, starting with ECMAScript Edition 6, let and const declarations allow you to create block-scoped variables.

The following example is not Functional Programming:


let counter = 0;

function count()
{
  return counter++;
}

console.log(count());
console.log(count());
console.log(count());

// 0
// 1
// 2

Optional arguments


function add(x, y) {
  var total = x + y;
  return total;
}

// Missing arguments will be taken as undefined:
add(); // output: NaN.
// You can't perform addition on undefined
add(2, 3, 4); // 5
// added the first two; 4 was ignored

// Functions have access to an additional variable inside their body called arguments:
function avg() {
  var sum = 0;
  for (var i = 0, j = arguments.length; i < j; i++) {
    sum += arguments[i];
  }
  return sum / arguments.length;
}

avg(2, 3, 4, 5); // 3.5

// If you want to pass in an array instead of a list of arguments:
avg.apply(null, [2, 3, 4, 5]); // 3.5
// apply() is a member method of any function object.

Another example.


function power(base, exponent) {
  if (exponent == undefined)
    exponent = 2;
  var result = 1;
  for (var count = 0; count < exponent; count++)
    result *= base;
  return result;
}

console.log(power(4));
// 16
console.log(power(4, 3));
// 64

Anonymouse functions


var avg = function() {
  var sum = 0;
  for (var i = 0, j = arguments.length; i < j; i++) {
    sum += arguments[i];
  }
  return sum / arguments.length;
};
// Semantically equivalent to the function avg() form in "optional arguments".

// Since javascript block can't make variables local,
// A way of "hiding" some local variables, like block scope in C:

var a = 1;
var b = 2;

(function() {
  var b = 3;
  a += b;
})();

a; // 4
b; // 2

Recursive functions

JavaScript allows you to call functions recursively. This is particularly useful for dealing with tree structures, such as those found in the browser DOM.


function power(base, exponent) {
  if (exponent == 0)
    return 1;
  else
    return base * power(base, exponent - 1);
};

console.log(power(2, 3));
// 8

function countChars(elm) {
  if (elm.nodeType == 3) { // TEXT_NODE
    return elm.nodeValue.length;
  }
  var count = 0;
  for (var i = 0, child; child = elm.childNodes[i]; i++) {
    count += countChars(child);
  }
  return count;
}

This highlights a potential problem with anonymous functions: how do you call them recursively if they don't have a name? JavaScript lets you name function expressions for this. You can use named IIFEs (Immediately Invoked Function Expressions) as shown below:


var charsInBody = (function counter(elm) {
  if (elm.nodeType == 3) { // TEXT_NODE
    return elm.nodeValue.length;
  }
  var count = 0;
  for (var i = 0, child; child = elm.childNodes[i]; i++) {
    count += counter(child);
  }
  return count;
})(document.body);

The name provided to a function expression ("counter" in the above) is only available to the function's own scope. This allows more optimizations to be done by the engine and results in more readable code.

Invocation

About This

Normal invocation

The code in a function is not executed when the function is defined. It is executed when the function is invoked.


function myFunction(a, b) {
    return a * b;
}

myFunction(10, 2); // 20
window.myFunction(10, 2); // 20

function myFunction() {
    return this;
}
myFunction(); // Return the "window" object.
// NOTE: Using the window object as a variable can easily crash your program.

var myObject = {
  firstName:"John",
  lastName: "Doe",
  fullName: function () {
    return this;
  }
}
myObject.fullName(); // Return { firstName: 'John', lastName: 'Doe', fullName: [Function] }, e.g. the owner object.

Invoke with Function Constructors

If a function invocation is preceded with the new keyword, it is a constructor invocation.

The this keyword in the constructor does not have a value. The value of this will be the new object created when the function is invoked.


// This is a function constructor:
function myFunction(arg1, arg2) {
    this.firstName = arg1;
    this.lastName  = arg2;
}

// This	creates a new object
var x = new myFunction("John","Doe");
x.firstName;     // Will return "John"

Closure

Global and Local vars

Being able to reference a specific instance of local variables in an enclosing function - is called closure.


//// Example 1.

// Because this function returns another function that has access to the "private" var i, the returned function is, effectively, "privileged."

function makeCounter() {
  // `i` is only accessible inside `makeCounter`.
  var i = 0;

  return function() {
    console.log( ++i );
  };
}

// Note that `counter` and `counter2` each have their own scoped `i`.

var counter = makeCounter();
counter(); // logs: 1
counter(); // logs: 2

var counter2 = makeCounter();
counter2(); // logs: 1
counter2(); // logs: 2

i; // ReferenceError: i is not defined (it only exists inside makeCounter)

////////////////////////////////////////
//// Example 2

function multiplier(factor) {
  return function(number) {
    return number * factor;
  };
}

var twice = multiplier(2);
console.log(twice(5));
// 10

//////////////////////////////
/// Example 3

function person(name) {
  function get() {
    return name;
  }
  
  function set(newName) {
    name = newName;
  }
  
  return [get, set];
}

var getSetDave = person('Dave');
var getDave = getSetDave[0];
var setDave = getSetDave[1];

alert(getDave()); //'Dave'
setDave('Bob');
alert(getDave()); //'Bob'

var getSetMary = person('Mary');
var getMary = getSetMary[0];
var setMary = getSetMary[1];

alert(getMary()); //'Mary'

IIFE

References

Acronyms:

The heart of the matter

whether you define a function like function foo(){} or var foo = function(){}, what you end up with is an identifier (here foo) for a function.


var foo = function(){ /* code */ }

// How about call the function expression directly, just by putting () after it?

function(){ /* code */ }();
// SyntaxError: Unexpected token (

When the parser encounters the function keyword in the global scope or inside a function, it treats it as a function declaration (statement), and not as a function expression, by default. In the example before, it sees what it thinks to be a function declaration without a name and throws a SyntaxError exception because function declarations require a name.

Tricks to achive IIFE

The following three cases all work:


// () as group operator.
(
  function foo() {
    console.log("Hello world!");
  }()
)

// , as comma operator.
1,function foo() {
    console.log("Hello world!");
  }()

// [] as list operator.
[
  function foo() {
    console.log("Hello world!");
  }()
]

//////////////////////////////
// Collections of tricks.

// Parens

(function(){ /* code */ }()); // Crockford recommends this one
(function(){ /* code */ })(); // But this one works just as well

// When the parser already expects an expression:
// (But it is still recommended to add parens here for conventions and easy-for-read.)

var i = function(){ return 10; }(); // Here i is the return value of the function, but not the function itself!
true && function(){ /* code */ }();
0, function(){ /* code */ }();

// If you don't care about the return value, or the possibility of making your code slightly harder to read, you can save a byte by just prefixing the function with a unary operator.

!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();

// Here's another variation, from @kuvos - I'm not sure of the performance implications, if any, of using the `new` keyword, but it works.
// http://twitter.com/kuvos/status/18209252090847232

new function(){ /* code */ }
new function(){ /* code */ }() // Only need parens if passing arguments

Examples


// This doesn't work like you might think, because the value of `i` never gets locked in.
// Instead, every link, when clicked (well after the loop has finished executing), alerts the total number of elements, because that's what the value of `i` actually is at that point.

var elems = document.getElementsByTagName( 'a' );
for ( var i = 0; i < elems.length; i++ ) {
  elems[ i ].addEventListener( 'click', function(e){
    e.preventDefault();
    alert( 'I am link #' + i );
  }, 'false' );
}

// This works, because inside the IIFE, the value of `i` is locked in as `lockedInIndex`.

var elems = document.getElementsByTagName( 'a' );
for ( var i = 0; i < elems.length; i++ ) {
  (function( lockedInIndex ){
    elems[ i ].addEventListener( 'click', function(e){
      e.preventDefault();
      alert( 'I am link #' + lockedInIndex );
    }, 'false' );
  })( i );
}

// Or this also works
for ( var i = 0; i < elems.length; i++ ) {
  elems[ i ].addEventListener( 'click', (function( lockedInIndex ){
    return function(e){
      e.preventDefault();
      alert( 'I am link #' + lockedInIndex );
    };
  })( i ), 'false' );
}

Used in the Module Pattern


var counter = (function(){
  var i = 0;

  return {
    get: function(){
      return i;
    },
    set: function( val ){
      i = val;
    },
    increment: function() {
      return ++i;
    }
  };
}());

// `counter` is an singleton object with properties (here are all methods).

counter.get(); // 0
counter.set( 3 );
counter.increment(); // 4
counter.increment(); // 5

counter.i; // undefined (`i` is not a property of the returned object)
i; // ReferenceError: i is not defined (it only exists inside the closure)

OOP: Use functions as classes

JavaScript is a prototype-based language that contains no class statement, as you'd find in C++ or Java. Instead, JavaScript uses functions as classes.

Let's consider a person object with first and last name fields. There are two ways in which the name might be displayed: as "first last" or as "last, first". Using the functions and objects that we've discussed previously, we could display the data like this:


function makePerson(first, last) {
  return {
    first: first,
    last: last
  };
}
function personFullName(person) {
  return person.first + ' ' + person.last;
}
function personFullNameReversed(person) {
  return person.last + ', ' + person.first;
}

s = makePerson("Simon", "Willison");
personFullName(s); // "Simon Willison"
personFullNameReversed(s); // "Willison, Simon"

This works, but it's pretty ugly. You end up with dozens of functions in your global namespace. What we really need is a way to attach a function to an object. Since functions are objects, this is easy:


function makePerson(first, last) {
  return {
    first: first,
    last: last,
    fullName: function() {
      return this.first + ' ' + this.last;
    },
    fullNameReversed: function() {
      return this.last + ', ' + this.first;
    }
  };
}

s = makePerson("Simon", "Willison")
s.fullName(); // "Simon Willison"
s.fullNameReversed(); // "Willison, Simon"

There's something here we haven't seen before: the this keyword. Used inside a function, this refers to the current object. What that actually means is specified by the way in which you called that function. If you called it using dot notation or bracket notation on an object, that object becomes this. If dot notation wasn't used for the call, this refers to the global object.

Note that this is a frequent cause of mistakes. For example:


s = makePerson("Simon", "Willison");
var fullName = s.fullName;
fullName(); // undefined undefined

When we call fullName() alone, without using s.fullName(), this is bound to the global object. Since there are no global variables called first or last we get undefined for each one.

Constructor

We can take advantage of the this keyword to improve our makePerson function:


function Person(first, last) {
  this.first = first;
  this.last = last;
  this.fullName = function() {
    return this.first + ' ' + this.last;
  };
  this.fullNameReversed = function() {
    return this.last + ', ' + this.first;
  };
}
var s = new Person("Simon", "Willison");

We have introduced another keyword: new. new is strongly related to this. It creates a brand new empty object, and then calls the function specified, with this set to that new object. Notice though that the function specified with this does not return a value but merely modifies the this object. It's new that returns the this object to the calling site.

Functions that are designed to be called by new are called constructor functions. Common practice is to capitalize these functions as a reminder to call them with new.

Shared methods defined through "prototype"

The improved function still has the same pitfall with calling fullName() alone.

Our person objects are getting better, but there are still some ugly edges to them. Every time we create a person object we are creating two brand new function objects within it -- wouldn't it be better if this code was shared?


function personFullName() {
  return this.first + ' ' + this.last;
}
function personFullNameReversed() {
  return this.last + ', ' + this.first;
}
function Person(first, last) {
  this.first = first;
  this.last = last;
  this.fullName = personFullName;
  this.fullNameReversed = personFullNameReversed;
}

That's better: we are creating the method functions only once, and assigning references to them inside the constructor. Can we do any better than that? The answer is yes:


function Person(first, last) {
  this.first = first;
  this.last = last;
}
Person.prototype.fullName = function() {
  return this.first + ' ' + this.last;
};
Person.prototype.fullNameReversed = function() {
  return this.last + ', ' + this.first;
};

Person.prototype is an object shared by all instances of Person. It forms part of a lookup chain (that has a special name, "prototype chain"): any time you attempt to access a property of Person that isn't set, JavaScript will check Person.prototype to see if that property exists there instead. As a result, anything assigned to Person.prototype becomes available to all instances of that constructor via the this object.

This is an incredibly powerful tool. JavaScript lets you modify something's prototype at any time in your program, which means you can add extra methods to existing objects at runtime:


s = new Person("Simon", "Willison");
s.firstNameCaps(); // TypeError on line 1: s.firstNameCaps is not a function

Person.prototype.firstNameCaps = function firstNameCaps() {
  return this.first.toUpperCase()
};
s.firstNameCaps(); // "SIMON"

Interestingly, you can also add things to the prototype of built-in JavaScript objects. Let's add a method to String that returns that string in reverse:


var s = "Simon";
s.reversed(); // TypeError on line 1: s.reversed is not a function

String.prototype.reversed = function reversed() {
  var r = "";
  for (var i = this.length - 1; i >= 0; i--) {
    r += this[i];
  }
  return r;
};

s.reversed(); // nomiS

// Our new method even works on string literals!
"This can now be reversed".reversed(); // desrever eb won nac sihT

As mentioned before, the prototype forms part of a chain. The root of that chain is Object.prototype, whose methods include toString() - it is this method that is called when you try to represent an object as a string. This is useful for debugging our Person objects:


var s = new Person("Simon", "Willison");
s; // [object Object]

Person.prototype.toString = function() {
  return '<Person: ' + this.fullName() + '>';
}

s.toString(); // "<Person: Simon Willison>"

Remember how avg.apply() had a null first argument? We can revisit that now. The first argument to apply() is the object that should be treated as 'this'. For example, here's a trivial implementation of new:


function trivialNew(constructor, ...args) {
  var o = {}; // Create an object
  constructor.apply(o, args);
  return o;
}

This isn't an exact replica of new as it doesn't set up the prototype chain (it would be difficult to illustrate). This is not something you use very often, but it's useful to know about. In this snippet, ...args (including the ellipsis) is called the "rest arguments" — as the name implies, this contains the rest of the arguments.

Calling


var bill = trivialNew(Person, "William", "Orange");
// is therefore almost equivalent to
var bill = new Person("William", "Orange");

apply() has a sister function named call(), which again lets you set this but takes an expanded argument list as opposed to an array.


function lastNameCaps() {
  return this.last.toUpperCase();
}
var s = new Person("Simon", "Willison");
lastNameCaps.call(s);
// Is the same as:
s.lastNameCaps = lastNameCaps;
s.lastNameCaps();

var Person = function (firstName) {
  this.firstName = firstName;
};

Person.prototype.sayHello = function() {
  console.log("Hello, I'm " + this.firstName);
};

var person1 = new Person("Alice");
var person2 = new Person("Bob");
var helloFunction = person1.sayHello;

// logs "Hello, I'm Alice"
person1.sayHello();

// logs "Hello, I'm Bob"
person2.sayHello();

// logs "Hello, I'm undefined" (or fails with a TypeError in strict mode)
helloFunction();                                    

// logs true
console.log(helloFunction === person1.sayHello);

// logs true
console.log(helloFunction === Person.prototype.sayHello);

// logs "Hello, I'm Alice"
helloFunction.call(person1);

call, apply, bind

zhihu.


function myFunction(a, b) {
  return a * b;
}
var a;

myObject = myFunction.call(a, 10, 2); // 20

myArray = [10, 2];
myObject = myFunction.apply(a, myArray); // 20

// A practical example:

function changeStyle(attr, value) {
  this.style[attr] = value;
}
var box = document.getElementById('box');
window.changeStyle.call(box, "height", "200px");

Namespace

In JavaScript a namespace is just another object containing methods, properties, and objects.


// global namespace
var MYAPP = MYAPP || {};

// sub namespace
MYAPP.event = {};

In the above code sample, we first checked whether MYAPP is already defined (either in same file or in another file). If yes, then use the existing MYAPP global object, otherwise create an empty object called MYAPP which will encapsulate methods, functions, variables, and objects.

Inheritance

In JavaScript you do this by assigning an instance of the parent class to the child class, and then specializing it. In modern browsers you can also use Object.create to implement inheritance.

In the example below, we define the class Student as a child class of Person. Then we redefine the sayHello() method and add the sayGoodBye() method.


// Define the Person constructor
var Person = function(firstName) {
  this.firstName = firstName;
};

// Add a couple of methods to Person.prototype
Person.prototype.walk = function(){
  console.log("I am walking!");
};

Person.prototype.sayHello = function(){
  console.log("Hello, I'm " + this.firstName);
};

// Define the Student constructor
function Student(firstName, subject) {
  // Call the parent constructor, making sure (using call) that "this" is set correctly during the call
  Person.call(this, firstName);

  // Initialize our Student-specific properties
  this.subject = subject;
}

// Create a Student.prototype object that inherits from Person.prototype.
// Note: A common error here is to use "new Person()" to create the Student.prototype. That's incorrect for several reasons, not least that we don't have anything to give Person for the "firstName" argument. The correct place to call Person is above, where we call it from Student.
Student.prototype = Object.create(Person.prototype); // See note below

// Set the "constructor" property to refer to Student
Student.prototype.constructor = Student;

// Replace the "sayHello" method
Student.prototype.sayHello = function(){
  console.log("Hello, I'm " + this.firstName + ". I'm studying "
              + this.subject + ".");
};

// Add a "sayGoodBye" method
Student.prototype.sayGoodBye = function(){
  console.log("Goodbye!");
};

// Example usage:
var student1 = new Student("Janet", "Applied Physics");
student1.sayHello();   // "Hello, I'm Janet. I'm studying Applied Physics."
student1.walk();       // "I am walking!"
student1.sayGoodBye(); // "Goodbye!"

// Check that instanceof works correctly
console.log(student1 instanceof Person);  // true 
console.log(student1 instanceof Student); // true

Regarding the Student.prototype = Object.create(Person.prototype); line: On older JavaScript engines without Object.create, one can either use a "polyfill" (aka "shim", see the linked article), or one can use a function that achieves the same result, such as:


function createObject(proto) {
    function ctor() { }
    ctor.prototype = proto;
    return new ctor();
}

// Usage:
Student.prototype = createObject(Person.prototype);

Abstraction

Abstraction is a mechanism that allows you to model the current part of the working problem, either by inheritance (specialization) or composition.


var foo = function () {};

// logs "foo is a Function: true"
console.log('foo is a Function: ' + (foo instanceof Function));

// logs "foo.prototype is an Object: true"
console.log('foo.prototype is an Object: ' + (foo.prototype instanceof Object));

Inner functions

JavaScript function declarations are allowed inside other functions. An important detail of nested functions in JavaScript is that they can access variables in their parent function's scope:


function betterExampleNeeded() {
  var a = 1;
  function oneMoreThanA() {
    return a + 1;
  }
  return oneMoreThanA();
}

If a function relies on one or two other functions that are not useful to any other part of your code, you can nest those utility functions inside the function that will be called from elsewhere. This keeps the number of functions that are in the global scope down, which is always a good thing.

This is also a great counter to the lure of global variables. When writing complex code it is often tempting to use global variables to share values between multiple functions — which leads to code that is hard to maintain. Nested functions can share variables in their parent, so you can use that mechanism to couple functions together when it makes sense without polluting your global namespace — "local globals" if you like. This technique should be used with caution, but it's a useful ability to have.

Closures

It is one of the most powerful abstractions that JavaScript has to offer.


function makeAdder(a) {
  return function(b) {
    return a + b;
  };
}
var x = makeAdder(5);
var y = makeAdder(20);
console.log(x(6)); // 11
console.log(y(7)); // 27

What's happening here is pretty much the same as was happening with the inner functions earlier on: a function defined inside another function has access to the outer function's variables. The only difference here is that the outer function has returned, and hence common sense would seem to dictate that its local variables no longer exist. But they do still exist - otherwise the adder functions would be unable to work. What's more, there are two different "copies" of makeAdder()'s local variables — one in which a is 5 and one in which a is 20.

Here's what's actually happening. Whenever JavaScript executes a function, a 'scope' object is created to hold the local variables created within that function. It is initialized with any variables passed in as function parameters. This is similar to the global object that all global variables and functions live in, but with a couple of important differences: firstly, a brand new scope object is created every time a function starts executing, and secondly, unlike the global object (which is accessible as this and in browsers as window) these scope objects cannot be directly accessed from your JavaScript code. There is no mechanism for iterating over the properties of the current scope object, for example.

So when makeAdder() is called, a scope object is created with one property: a, which is the argument passed to the makeAdder() function. makeAdder() then returns a newly created function. Normally JavaScript's garbage collector would clean up the scope object created for makeAdder() at this point, but the returned function maintains a reference back to that scope object. As a result, the scope object will not be garbage collected until there are no more references to the function object that makeAdder() returned.

Scope objects form a chain called the scope chain, similar to the prototype chain used by JavaScript's object system.

A closure is the combination of a function and the scope object in which it was created. Closures let you save state — as such, they can often be used in place of objects.

Builtin Functions/Objects

eval

SO.


var a = 1;
var name = 'a';
document.write(eval(name)); // 1

eval(new String("2 + 2")); // returns a String object containing "2 + 2"
eval("2 + 2");             // returns 4

Tips

Debug


<script>
a = 5;
b = 6;
c = a + b;
console.log(c);
</script>

Find all elements with id

Stackoverflow ref.


var inputs = document.getElementsByTagName("input");
for (var i = 0; i < inputs .length; i++) {
  alert(inputs[i].id);
}

HTML DOM

In the HTML DOM (Document Object Model), everything is a node:

In the HTML DOM, the Element object represents an HTML element.

Window Navigator

The window.navigator object contains information about the visitor's browser. For a full list see w3schools: object of navigator.

appCodeName 	Returns the code name of the browser
appName 	Returns the name of the browser
appVersion 	Returns the version information of the browser
cookieEnabled 	Determines whether cookies are enabled in the browser
geolocation 	Returns a Geolocation object that can be used to locate the user's position
language 	Returns the language of the browser
onLine 	Determines whether the browser is online
platform 	Returns for which platform the browser is compiled
product 	Returns the engine name of the browser
userAgent 	Returns the user-agent header sent by the browser to the server
javaEnabled() 	Specifies whether or not the browser has Java enabled

JS BOM

Browser Object Model (BOM).

JS window

Location

w3school.

location.hostname 返回 web 主机的域名
location.pathname 返回当前页面的路径和文件名
location.port 返回 web 主机的端口 (80 或 443)
location.protocol 返回所使用的 web 协议(http:// 或 https://)
location.href 属性返回当前页面的 URL。

Refulz.

For URL http://www.refulz.com:8082/index.php#tab2

Property 	Result
------		------
host 	www.refulz.com:8082
hostname 	www.refulz.com
port 	8082
protocol 	http
pathname 	index.php
href 	http://www.refulz.com:8082/index.php#tab2
hash 	#tab2

GetURL.


# Inspecting the location object:
location = {
  host: "stackoverflow.com",
  hostname: "stackoverflow.com",
  href: "http://stackoverflow.com/questions/2300771/jquery-domain-get-url",
  pathname: "/questions/2300771/jquery-domain-get-url",
  port: "",
  protocol: "http:"
}

console.log(location.hostname);
console.log(document.domain);

console.log("document.URL : "+document.URL);
console.log("document.location.href : "+document.location.href);
console.log("document.location.origin : "+document.location.origin);
console.log("document.location.hostname : "+document.location.hostname);
console.log("document.location.host : "+document.location.host);
console.log("document.location.pathname : "+document.location.pathname);

Events

window.onload, document.onload

The general idea is that window.onload fires when the document's window is ready for presentation and document.onload fires when the DOM tree (built from the markup code within the document) is completed. http://stackoverflow.com/questions/588040/window-onload-vs-document-onload.


<!DOCTYPE html>
<html>
<body>

<h1 id="header">Old Header</h1>

<script>
// Note: not getElementByID, nor getElementsById!
var element = document.getElementById("header");
element.innerHTML = "New Header";
</script>

</body>
</html>

function showPic() {
	var placeholder = document.getElementById('placeholder');
	placeholder.setAttribute('src',src);
}

window.onload = showPic;

FAQ

Display XML

mozilla developer.


var inp = document.createElement('input');
var XMLS = new XMLSerializer();
var inp_xmls = XMLS.serializeToString(inp); // First convert DOM node into a string.

// Insert a newly created node into the document's body
document.body.insertAdjacentHTML('afterbegin', inp_xmls);
alert(inp_xmls);

$.ajax({
  type: theForm.attr('method'),
  url: theForm.attr("action"),
  data: subscribeEventStr,
  contentType: "application/xml; charset=utf-8",
  dataType : "xml",
  success: function(data)
  {
    $("pre#subscribeRes").html(htmlEntities(new XMLSerializer().serializeToString(data)));
  },
  failure: function(data)
  {
    $("pre#subscribeRes").html(htmlEntities(new XMLSerializer().serializeToString(data)));
  }
});

Another option: Fetch your XML using Ajax and simply put the result in a textarea. Style the textarea any way you want. SO: display XML in JS.

How to make async JS load in order?

Use "defer" instead of "async".

gfw.js


function FindProxyForURL(url, host) {
  var lastPos;
  do {
    if (domains.hasOwnProperty(host)) {
        return proxy;
    }
    lastPos = host.indexOf('.') + 1;
    host = host.slice(lastPos);
  } while (lastPos >= 1);
  return direct;
}

Speed Boost

Normal

You can place an external script reference in head or body as you like.
The script will behave as if it was located exactly where the script tag is located.

window.load event

Another solution is to set your function to the window.onload event.
This is not a good solution, because it waits until all images and iframes finished downloading too.


function f1 () {console.log("f1 called");};
function f2 () {console.log("f2 called");};

window.addEventListener("load", f1 , false);
window.addEventListener("load", f2 , false);
// Or old school
window.onload = function(){
    f1();
    f2();
};

Async, Defer

The current state-of-the-art is to put scripts in the head tag and use the "async" or "defer" attributes.


<!-- async, executed asynchronously, not in order -->
<script type="text/javascript" src="path/to/script1.js" async></script>
<script type="text/javascript" src="path/to/script2.js" async></script>
<!-- defer, executed after page load, in order -->
<script type="text/javascript" src="path/to/script1.js" defer></script>
<script type="text/javascript" src="path/to/script2.js" defer></script>