All notes
Javascrip

Intro

Born in 1995, mainly used to process input validation which was previously done by perl on the server side.

ECMAScript

JS consists of three components:

ECMAScript defines syntax, datatype, keywords, operators, etc. It has no reference to browsers.

Web browser is just one of the hosts for ECMAScript. The host provides basic ECMAScript parsing, and also give extensions (for example, DOM) to let the language to interact with the environment. The other hosts include: Node, Adobe Flash.

ECMAScript has several realization: Javascript, Adobe ActionScript.

Good frameworks

If we can achieve fast-booting, low-memory, smooth-executing frameworks with good ergonomics we’ll be onto a winner. Until then, for mobile at least, I’ll be sticking to the vanilla web platform. https://aerotwist.com/blog/the-cost-of-frameworks/?utm_source=com.ideashower.readitlater.pro&utm_medium=social

Concepts

Polyfill

SO: what is the meaning of polyfills.

A polyfill is a browser fallback, made in JavaScript, that allows functionality you expect to work in modern browsers to work in older browsers, e.g., to support canvas (an HTML5 feature) in older browsers.

remysharp.com: what is a polyfill. It is written by the namer of "polyfill" explaining why he had chosen this word.

A polyfill is a piece of code (or plugin) that provides the technology that you, the developer, expect the browser to provide natively. Flattening the API landscape if you will.

Shim, to me, meant a piece of code that you could add that would fix some functionality, but it would most often have it's own API.

...

Poly meaning it could be solved using any number of techniques - it wasn't limited to just being done using JavaScript, and fill would fill the hole in the browser where the technology needed to be. It also didn't imply "old browser" (because we need to polyfill new browser too).

Also for me, the product Polyfilla (spackling in the US) is a paste that can be put in to walls to cover cracks and holes. I really liked that idea of visualising how we're fixing the browser. Once the wall is flat, you can paint as you please or wallpaper to your heart's content.

...

Here's an example: sessionStorage is available in all the latest browsers (IE8 and upwards) but isn't in IE7 and below.

A polyfill can be used to plug the support for older browsers that don't provide sessionStorage.

Now with the polyfiller in place, as a developer I can rely on using the Web Storage API (for sessions) and not have to feature test in my code or fork to handle different situations.

Another example is providing canvas support in IE. ...

github.com: modernizr, a collection of polyfills.

Shim

2ality.com: shim vs polyfill.

A shim is a library that brings a new API to an older environment, using only the means of that environment.

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"};

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

null, undefined

"undefined" really means undefined. Not False, not True, not 0, not empty string. So when you compare undefined to anything, the result is always false, it is not equal to that.

SO: javascript check for null vs undefined.



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

// global scope
var theFu; // theFu has been declared, but its value is undefined
typeof theFu; // "undefined"
"theFu" in window; // true
"theFoo" in window; // false

//---------- Used in if clause:

if (a === null)
// or
if (a == null) // will also be true if a is undefined.

if (typeof a === "undefined")
// or
if (a === undefined)
// or
if (a == undefined) // will also be true if a is null.

// The usual way to check for those is to use the fact that they're falsey:
if (!a) {
    // `a` is falsey, which includes `undefined` and `null`
    // (and `""`, and `0`, and `NaN`, and [of course] `false`)
}

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"

"hehe".includes('a');

// http://stackoverflow.com/questions/21895233/how-in-node-to-split-string-by-newline-n
"a\nb\r\nc".split(/\r?\n/);
// [ 'a', 'b', 'c' ]

// http://stackoverflow.com/questions/94037/convert-character-to-ascii-code-in-javascript
"\n".charCodeAt(0);
// 10
String.fromCharCode(10);
// "\n"

////////// Coffeescript:

// If there is some strange chars, you can inspect by:
for i in str
  console.log(i.charCodeAt(0));

// e.g. "‎" Symbol Name: Left-To-Right Mark. http://www.codetable.net/decimal/8206.

unless String::trim then String::trim = -> @replace /^\s+|\s+$/g, ""

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

Object

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

Iterate through object's properties



for (var property in object) {
  if (object.hasOwnProperty(property)) {
    // do stuff
  }
}

delete, remove an item from an obj



var test = {'red':'#FF0000', 'blue':'#0000FF'};
delete test.blue; // or use => delete test['blue'];
console.log(test);

defineProperty, defineProperties



//---------- defineProperty

const object1 = {};

Object.defineProperty(object1, 'property1', {
  value: 42,
  writable: false
});

object1.property1 = 77;
// throws an error in strict mode

console.log(object1.property1);
// expected output: 42

//---------- defineProperties

const object1 = {};

Object.defineProperties(object1, {
  property1: {
    value: 42,
    writable: true
  },
  property2: {}
});

console.log(object1.property1);
// expected output: 42

freeze

It prevents new properties from being added to it; prevents existing properties from being removed; and prevents existing properties, or their enumerability, configurability, or writability, from being changed, it also prevents the prototype from being changed.



const object1 = {
  property1: 42
};

const object2 = Object.freeze(object1);

object2.property1 = 33;
// Throws an error in strict mode

console.log(object2.property1);
// expected output: 42

getPrototypeOf



var proto = {};
var obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true

hasOwnProperty

developer.mozilla.org: Object hasOwnProperty.


o = new Object();
o.prop = 'exists';

function changeO() {
  o.newprop = o.prop;
  delete o.prop;
}

o.hasOwnProperty('prop');   // returns true
changeO();
o.hasOwnProperty('prop');   // returns false

// Unlike the "in" operator, this method does not check down the object's prototype chain, e.g. no inherited property is checked.
o = new Object();
o.prop = 'exists';
o.hasOwnProperty('prop');             // returns true
o.hasOwnProperty('toString');         // returns false
o.hasOwnProperty('hasOwnProperty');   // returns false

prototype, __proto__, class

Object.prototype

The Object.prototype property represents the Object "prototype" object.

A typical object inherits properties (including methods) from Object.prototype. However, an Object may be deliberately created for which this is not true (e.g. by Object.create(null)), or it may be altered so that this is no longer true (e.g. with Object.setPrototypeOf).


Date.prototype.lol = function() {
 alert('hi');
};

( new Date ).lol() // alert message
extend()

extend is usually a high level function ("high level function" meaning .extend isn't built-in but often provided by a library such as jQuery or Prototype) that copies the prototype of a new subclass that you want to extend from the base class.

So you can do something like:


extend( Fighter, Human );
// And the Fighter constructor/object will inherit the prototype of Human, so if you define methods such as live and die on Human then Fighter will also inherit those.
JS is prototype-based

JavaScript remains prototype-based, not class-based. The "class" keyword is introduced in ES2015, but is syntactical sugar.

hackernoon.com: prototypes in JS.



// A construction function, or a class?
function Human(firstName, lastName) {
	this.firstName = firstName,
	this.lastName = lastName,
	this.fullName = function() {
		return this.firstName + " " + this.lastName;
	}
}

var person1 = new Human("Virat", "Kohli");
var person2 = new Human("Sachin", "Tendulkar");

person1 === person2 // false
Human.prototype === person1.__proto__ //true
Human.prototype === person2.__proto__ //true
person1.__proto__ === person2.__proto__ //true

// Prototype object of the constructor function is shared among all the objects created using the constructor function, to save memory.

//---------- prototype is also an object:

//Dot notation
Human.prototype.name = "Ashwin";
console.log(Human.prototype.name); //Output: Ashwin
//Square bracket notation
Human.prototype["age"] = 26;
console.log(Human.prototype["age"]); //Output: 26

person1.age // "26"
person1.name // "Ashwin"

//---------- Precedence, property shadowing

// In the previous example, when person1.name is called, JavaScript engine checks if the property exists on the object 'person1'. In this case, name property was not on 'person1'. So, now JavaScript engine checks if the name property exists on the dunder proto property or the prototype of 'person1'.

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain

// Let's create an object o from function f with its own properties a and b:
let f = function () {
   this.a = 1;
   this.b = 2;
}
let o = new f(); // {a: 1, b: 2}
//add properties in f function's prototype
f.prototype.b = 3;
f.prototype.c = 4;

console.log(o.a); // 1
// Is there an 'a' own property on o? Yes, and its value is 1.

console.log(o.b); // 2
// Is there a 'b' own property on o? Yes, and its value is 2.
// The prototype also has a 'b' property, but it's not visited. 
// This is called "property shadowing."

console.log(o.c); // 4
// Is there a 'c' own property on o? No, check its prototype.
// Is there a 'c' own property on o.[[Prototype]]? Yes, its value is 4.

console.log(o.d); // undefined
// Is there a 'd' own property on o? No, check its prototype.
// Is there a 'd' own property on o.[[Prototype]]? No, check its prototype.
// o.[[Prototype]].[[Prototype]] is null, stop searching,
// no property found, return undefined.

//---------- Problems with the prototype

// If an object A modifies property of the prototype having primitive value, other objects will not be effected by this as A will create a property on its objects as shown below.
console.log(person1.name);//Output: Ashwin
console.log(person2.name);//Output: Ashwin
person1.name = "Ganguly"; // Here since "name" is a primitive, it only changes person1's own property.
console.log(perosn1.name);//Output: Ganguly
console.log(person2.name);//Output: Ashwin

// However, in this example, there is a problem
function Person(){
}
Person.prototype.friends = ['Jadeja', 'Vijay'],//Arrays are of reference type in JavaScript
var person1= new Person();
var person2 = new Person();
person1.friends.push("Amit"); // Since 'friends' is an array, it will affect all the objects with the Person.prototype.
console.log(person1.friends);// Output: "Jadeja, Vijay, Amit"
console.log(person2.friends);// Output: "Jadeja, Vijay, Amit"

//---------- Best practise

//Define the object specific properties inside the constructor
function Human(name, age){
	this.name = name,
	this.age = age,
	this.friends = ["Jadeja", "Vijay"]
}
//Define the shared properties and methods using the prototype
Human.prototype.sayName = function(){
	console.log(this.name);
}
//Create two objects using the Human constructor function
var person1 = new Human("Virat", "Kohli");
var person2 = new Human("Sachin", "Tendulkar");

//Lets check if person1 and person2 have points to the same instance of the sayName function
console.log(person1.sayName === person2.sayName) // true

//Let's modify friends property and check
person1.friends.push("Amit");

console.log(person1.friends)// Output: "Jadeja, Vijay, Amit"
console.log(person2.frinds)//Output: "Jadeja, Vijay"

toPrimitive

developer.mozilla.org: toPrimitive.



// An object without Symbol.toPrimitive property.
var obj1 = {};
console.log(+obj1);     // NaN
console.log(`${obj1}`); // "[object Object]"
console.log(obj1 + ''); // "[object Object]"

// An object with Symbol.toPrimitive property.
var obj2 = {
  [Symbol.toPrimitive](hint) {
    if (hint == 'number') {
      return 10;
    }
    if (hint == 'string') {
      return 'hello';
    }
    return true;
  }
};
console.log(+obj2);     // 10        -- hint is "number"
console.log(`${obj2}`); // "hello"   -- hint is "string"
console.log(obj2 + ''); // "true"    -- hint is "default"

member functions



//---------- Object.values

var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.values(obj)); // ['a', 'b', 'c']

var an_obj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.values(an_obj)); // ['b', 'c', 'a']

// non-object argument will be coerced to an object
console.log(Object.values('foo')); // ['f', 'o', 'o']

//---------- Object.keys

var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']

// array like object
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']

Proxy

developer.mozilla.org: global objects: Proxy.


//---------- Basic
var handler = {
    get: function(target, name) {
        return name in target ?
            target[name] :
            37;
    }
};

var p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;

console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37

//---------- No-op forwarding

var target = {};
var p = new Proxy(target, {});

p.a = 37; // operation forwarded to the target
console.log(target.a); // 37. The operation has been properly forwarded

RegExp

developer.mozilla.org.



var myArray = /d(b+)d/g.exec('cdbbdbsbz'); // equivalent to "cdbbdbsbz".match(/d(b+)d/g);
# myArray: ["dbbd", "bb", index: 1, input: "cdbbdbsbz"]
typeof(myArray); // "object"
myArray.length; // 2
myArray[0]; // "dbbd"
myArray[1]; // "bb"
myArray[2]; // undefined

var myRe = new RegExp('d(b+)d', 'g'); // Construct a RegExp from a string.
var myArray = myRe.exec('cdbbdbsbz');

# Example from cross-env.
match=/(\w+)=('(.*)'|"(.*)"|(.*))/.exec('node=test');
# ["node=test", "node", "test", undefined, undefined, "test", index: 0, input: "node=test"]
# match[5] is set.
match=/(\w+)=('(.*)'|"(.*)"|(.*))/.exec('node="test"');
# ["node="test"", "node", ""test"", undefined, "test", undefined, index: 0, input: "node="test""]
# match[4] is set.

//---------- Line breaks

var match = /(\r|\n)(.+GOLDEN_TEXT.+)(\r|\n)/.exec(text);
console.log(match[2]);

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.

//----- Two dimensional array
// https://stackoverflow.com/questions/966225/how-can-i-create-a-two-dimensional-array-in-javascript
var items = [
  [1, 2],
  [3, 4],
  [5, 6]
];
console.log(items[0][0]); // 1

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

//---------- Find

//--- find
function isBigEnough(element) {
  return element >= 15;
}
[12, 5, 8, 130, 44].find(isBigEnough); // 130

//--- findIndex
var array1 = [5, 12, 8, 130, 44];
function findFirstLargeNumber(element) {
  return element > 13;
}
console.log(array1.findIndex(findFirstLargeNumber));
// expected output: 3

//--- indexOf
var a = [2, 9, 9]; 
a.indexOf(2); // 0 
a.indexOf(7); // -1
if (a.indexOf(7) === -1) {
  // element doesn't exist in array
}

//---------- Remove, delete, splice

var a = [1, 2];
delete a[a.indexOf(1)];
// [ <1 empty item>, 2 ]
// NOTE: Using delete may leave undefined holes in the array. Use splice() instead.

var a = [1, 2];
a.splice(a.indexOf(1), 1);
console.log(a);
// [2]

//---------- Iteration
// "not" recommended:
for (var i = 0; i < a.length; i++) {
  // Do something with a[i]
}
array1.forEach(function(element) {
  console.log(element);
});
// 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' ]

map

developer.mozilla.org.



var new_array = arr.map(function callback(currentValue, index, array) {
    // Return element for new_array
}[, thisArg])

// Parameters:
// callback: Function that produces an element of the new Array, taking three arguments:
//   currentValue: The current element being processed in the array.
//   index [Optional]: The index of the current element being processed in the array.
//   array [Optional]: The array map was called upon.
// thisArg [Optional]: Value to use as this when executing callback.

Slice

mozilla.org: array slice.


var fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];
var citrus = fruits.slice(1, 3); // NOTE: the end is not included in result. It's [1, 3). See below result.
// citrus contains ['Orange','Lemon'].

// Therefore we can use this to convert array-like to array:
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
function list() {
  return Array.prototype.slice.call(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
// arguments is array-like since it supports [int] operators. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments

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

==, ===, Object.is

developer.mozilla.org: equality comparisons.

Loose equality ("double equals") using ==. It will perform a type conversion.
Strict equality (or "triple equals" or "identity") using ===. Without type conversion, by simply always returning false if the types differ.
Object.is (new in ECMAScript 2015). Behave the same way as triple equals, but with special handling for NaN and -0 and +0 so that the last two are not said to be the same, while Object.is(NaN, NaN) will be true.
For any non-primitive objects x and y which have the same structure but are distinct objects themselves, all of the above forms will evaluate to false.


//----- Loose equality: ==
// Type conversion is executed.

123 == "123"; // true. Equal to: 123 === +"123". '+' is used as "ToNumber".
1 == true; // true
undefined == null; // true
var obj1 = {};
obj1 == '[object Object]'; // true. Equal to: obj1.toString() === '[object Object]'. 'toString' is used as "ToPrimitive".

//----- Comparison by reference

[]==[]; // false
{}=={}; // false
[]===[]; // false
{}==={}; // false

a={a:1}
b={a:1}
a==b // false. Here it is not ToPrimitive(a)===ToPrimitive(b), but only a===b. See the complete table on "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness".
a===b // false
Object.is(a,b); // false
// Only the same object/reference is equal.
c=a;
c==a; // true
c===a; // true
Object.is(a,c); // true

//----- Strict equality: ===
// To avoid type coercion: if the values have different types, they are considered unequal.

123 === "123"; // false
1 === true;    // false
undefined === null; // 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";

//----- Same-value equality: Object.is

var test = { a: 1 };
Object.is(test, test);       // true

Object.is(null, null);       // true

// Special Cases
Object.is(0, -0);            // false
Object.is(-0, -0);           // true
Object.is(NaN, 0/0);         // true

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

Compare with JSONP

SO: can anyone explain what jsonp is.

JSONP (JSON with Padding) is a method commonly used to bypass the cross-domain policies in web browsers.

You should look to use CORS where possible (i.e. your server or API supports it, and the browser support is adequate), as JSONP has inherent security risks.

JSONP requests are not dispatched using the XMLHTTPRequest and the associated browser methods. Instead a "script" tag is created, whose source is set to the target URL.


// JSONP Request:
var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';
document.getElementsByTagName("head")[0].appendChild(tag);

The difference between a JSON response and a JSONP response:



// JSON:
{ "bar": "baz" }

// JSONP:
foo( { "bar": "baz" } );

JSONP requests containing the callback parameter, so that the server knows the name of the function to wrap the response. This function must exist in the global scope at the time the "script" tag is evaluated by the browser.


// JSONP
// Assumes a response object { "bar" : "baz" }

// Foo is the callback. Should reside in global scope.
function foo(response) {
  document.getElementById("output").innerHTML = response.bar;
};

var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';

document.getElementsByTagName("head")[0].appendChild(tag);

By default jQuery requires you to include "&callback=?" in the URL of your AJAX request. jQuery will take the success function you specify, assign it a unique name, and publish it in the global scope. It will then replace the question mark ? in "&callback=?" with the name it has assigned.

Syntax

Comments

//=

SO.

How Sprockets handles comments

Use single-line (//) comments in JavaScript source files for comments that don't need to appear in the resulting concatenated output.
Use multiple-line (/* ... */) comments for comments that should appear in the resulting concatenated output, like copyright notices or descriptive headers.
PDoc (/** ... **/) documentation comments will not be included in the resulting concatenation.

Comments beginning with //= are treated by Sprockets as directives. Sprockets currently understands two directives, require and provide.

Operators

exclamation !

Double exclamation !!

SO.

Real World Example "Test IE version":



!!undefined // false
!!null // false
!!true // true
!!false // false

let isIE8 = false;  
isIE8 = !! navigator.userAgent.match(/MSIE 8.0/);  
console.log(isIE8); // returns true or false 

console.log(navigator.userAgent.match(/MSIE 8.0/));  
// returns null  

Property accessors

developer.mozilla.org: property accessors.


object.property
object['property']

instanceof

The instanceof operator tests whether the prototype property of a constructor appears anywhere in the prototype chain of an object.

Object.prototype.toString.call()



var A = function() {}

A.prototype = Object.create(Array.prototype)
var a = new A()
a.push(1) # Works
a[0] # Works

# Here is the difference
a instanceof Array # true
Object.prototype.toString.call(a) # "[object Object]"

if, switch



if (condition1) {
    block of code to be executed if condition1 is true
} else if (condition2) {
    block of code to be executed if the condition1 is false and condition2 is true
} else {
    block of code to be executed if the condition1 is false and condition2 is false
}

switch(expression) {
    case n:
        code block
        break;
    case n:
        code block
        break;
    default:
        code block
}

for



for (var i = 0; i < 9; i++) {
   console.log(i);
   // more statements
}

for...in



var obj = {a: 1, b: 2, c: 3};
    
for (const prop in obj) {
  console.log(`obj.${prop} = ${obj[prop]}`);
}

// Output:
// "obj.a = 1"
// "obj.b = 2"
// "obj.c = 3"

for...of



//---------- Array
let iterable = [10, 20, 30];

for (let value of iterable) {
  value += 1;
  console.log(value);
}
// 11
// 21
// 31

//---------- Map
let iterable = new Map([['a', 1], ['b', 2], ['c', 3]]);

for (let entry of iterable) {
  console.log(entry);
}
// ['a', 1]
// ['b', 2]
// ['c', 3]

for (let [key, value] of iterable) {
  console.log(value);
}
// 1
// 2
// 3

Difference with for...in

The for...in statement iterates over the enumerable properties of an object, in original insertion order. The for...of statement iterates over data that iterable object defines to be iterated over.



Object.prototype.objCustom = function() {}; 
Array.prototype.arrCustom = function() {};

let iterable = [3, 5, 7];
iterable.foo = 'hello';

for (let i in iterable) {
  console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom"
}

for (let i in iterable) {
  if (iterable.hasOwnProperty(i)) {
    console.log(i); // logs 0, 1, 2, "foo"
  }
}

for (let i of iterable) {
  console.log(i); // logs 3, 5, 7
}

Try, catch

SO: Get line number in try-catch.



function dumpError(err) {
  if (typeof err === 'object') {
    if (err.message) {
      console.log('\nMessage: ' + err.message)
    }
    if (err.stack) {
      console.log('\nStacktrace:')
      console.log('====================')
      console.log(err.stack);
    }
  } else {
    console.log('dumpError :: argument is not an object');
  }
}

try {
  not_defined.function_call();
} catch(err) {
  dumpError(err);
}

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.");

arguments



// arguments.length
function log( x ) {
  console.log( typeof x, arguments.length );
}
log(); // "undefined", 0
log( 1 ); // "number", 1
log( "1", "2", "3" ); // "string", 3

// arguments.callee
var awesome = function() { return arguments.callee; }
awesome() === awesome // true

Default pamameter


//---------- Vanilla

function foo(a, b) {
  a = typeof a !== 'undefined' ? a : 42;
  b = typeof b !== 'undefined' ? b : 'default_b';
}

//----------- ES2015

// Use default values if no value or undefined is passed.
function read_file(file, delete_after = false) {
  // Code
}

getter, setter

The get syntax binds an object property to a function that will be called when that property is looked up.



{get prop() { ... } }
{get [expression]() { ... } }

///// 1
var obj = {
  log: ['test'],
  get latest() {
    if (this.log.length == 0) return undefined;
    return this.log[this.log.length - 1];
  }
}
console.log(obj.latest); // Will return "test".
// If you want to remove the getter, you can just delete it:
delete obj.latest;

///// 2
// Using a computed property name

var expr = 'foo';
var obj = {
  get [expr]() { return 'bar'; }
};
console.log(obj.foo); // "bar"

mozilla.org. Getters give you a way to define a property of an object, but they do not calculate the property's value until it is accessed, and cache it for later access.

this



$( document ).ready(function() {
  // this refers to window.document
});
$( "a" ).click(function() {
  // this refers to an anchor DOM element
});

function scope() {
  console.log( this, arguments.length );
}
scope() // window, 0
scope.call( "foobar", [ 1, 2 ] ); // "foobar", 1
scope.apply( "foobar", [ 1, 2 ] ); // "foobar", 2
// Call() passes all arguments through as arguments to the function, while apply() accepts an array as the arguments.

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

Function properties

length, name



//---------- length
// The length property specifies the number of arguments expected by the function.
function func1() {}
console.log(func1.length); // expected output: 0
function func2(a, b) {}
console.log(func2.length); // expected output: 2

//---------- name
function doSomething() {}
doSomething.name; // "doSomething"

(new Function).name; // "anonymous"

Function.prototype

apply, call

apply() / call() calls a function with a given "this" value, and arguments provided as an array / individually.



//---------- apply()

var numbers = [5, 6, 2, 3, 7];

var max = Math.max.apply(null, numbers);
console.log(max); // expected output: 7
var min = Math.min.apply(null, numbers);
console.log(min); // expected output: 2

Use apply and call to call parent functions



var ParentClass = {
  a: function () {
    console.log("I am a in ParentClass.");
  }
};
var DerivedClass = Object.create(ParentClass);

DerivedClass.a = function () {
  DerivedClass.__proto__.a.apply(this, arguments);
  console.log("I am a in DerivedClass.");
};

DerivedClass.a();
// I am a in ParentClass.
// I am a in DerivedClass.

bind

mozilla: bind.

Function.prototype.bind(). The bind() method creates a new function that, when called, has its this keyword set to the provided value.



this.x = 9;    // this refers to global "window" object here in the browser
var module = {
  x: 81,
  getX: function() { return this.x; }
};

module.getX(); // 81

var retrieveX = module.getX;
retrieveX();   
// returns 9 - The function gets invoked at the global scope

// Create a new function with 'this' bound to module
// New programmers might confuse the
// global var x with module's property x
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81

react: events gives a good example why bind is needed.

Anonymouse functions



function A() {  }
console.log(A.name); // 'A' 
// While anonymous functions have an empty name property:
var B = function() {  };
console.log(B.name); // ''

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, inheritance, and prototype chain

developer.mozilla.org.

Inheriting properties



let f = function () {
   this.a = 1;
   this.b = 2;
}
let o = new f(); // {a: 1, b: 2}

// Do not set the prototype f.prototype = {b:3,c:4}; this will break the prototype chain.
f.prototype.b = 3;
f.prototype.c = 4;
// o.[[Prototype]] has properties b and c.
// o.[[Prototype]].[[Prototype]] is null. This is the end of the prototype chain, as null by definition, has no [[Prototype]].
// Thus, the full prototype chain looks like:
// {a: 1, b: 2} ---> {b: 3, c: 4} ---> null

console.log(o.a); // 1
// Is there an 'a' own property on o? Yes, and its value is 1.

console.log(o.b); // 2
// Is there a 'b' own property on o? Yes, and its value is 2.
// The prototype also has a 'b' property, but it's not visited. This is called "property shadowing."

console.log(o.c); // 4
// Is there a 'c' own property on o? No, check its prototype.
// Is there a 'c' own property on o.[[Prototype]]? Yes, its value is 4.

console.log(o.d); // undefined
// Is there a 'd' own property on o? No, check its prototype.
// Is there a 'd' own property on o.[[Prototype]]? No, check its prototype.
// o.[[Prototype]].[[Prototype]] is null, stop searching,
// no property found, return undefined.

Inheriting "methods", this



var o = {
  a: 2,
  m: function() {
    return this.a + 1;
  }
};

console.log(o.m()); // 3
// When calling o.m in this case, 'this' refers to o

var p = Object.create(o);
// p is an object that inherits from o

p.a = 4; // creates a property 'a' on p
console.log(p.m()); // 5
// when p.m is called, 'this' refers to p.
// So when p inherits the function m of o, 'this.a' means p.a, the property 'a' of p.

Different ways to create objects and the resulting prototype chain

Objects created with syntax constructs



var o = {a: 1};
// The newly created object o has Object.prototype as its [[Prototype]].
// o has no own property named 'hasOwnProperty'. hasOwnProperty is an own property of Object.prototype. So o inherits hasOwnProperty from Object.prototype.
// o ---> Object.prototype ---> null

var b = ['yo', 'whadup', '?'];
// Arrays inherit from Array.prototype. (which has methods indexOf, forEach, etc.)
// The prototype chain looks like:
// b ---> Array.prototype ---> Object.prototype ---> null

function f() {
  return 2;
}
// Functions inherit from Function.prototype. (which has methods call, bind, etc.)
// f ---> Function.prototype ---> Object.prototype ---> null

With a constructor

A "constructor" in JavaScript is "just" a function that happens to be called with the "new" operator.



function Graph() {
  this.vertices = [];
  this.edges = [];
}

Graph.prototype = {
  addVertex: function(v) {
    this.vertices.push(v);
  }
};

var g = new Graph();
// g is an object with own properties 'vertices' and 'edges'.
// g.[[Prototype]] is the value of Graph.prototype when new Graph() is executed.

With Object.create



var a = {a: 1}; 
// a ---> Object.prototype ---> null

var b = Object.create(a);
// b ---> a ---> Object.prototype ---> null
console.log(b.a); // 1 (inherited)

var c = Object.create(b);
// c ---> b ---> a ---> Object.prototype ---> null

var d = Object.create(null);
// d ---> null
console.log(d.hasOwnProperty); 
// undefined, because d doesn't inherit from Object.prototype
Use it for Global config object

sitepoint.com.



var baseConfig = {
    'ck': '...',
    'nk': '...',
    'etc': '...',
};

var videoPluginConfig = Object.create(baseConfig);

// reading ck inherits from base
console.log(videoPluginConfig.ck);

// writing ck affects only videoPluginConfig
videoPluginConfig.ck = 'special_context';

With the class keyword

Introduced in ECMAScript 2015.



'use strict';

class Polygon {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

class Square extends Polygon {
  constructor(sideLength) {
    super(sideLength, sideLength);
  }
  get area() {
    return this.height * this.width;
  }
  set sideLength(newLength) {
    this.height = newLength;
    this.width = newLength;
  }
}

var square = new Square(2);

Performance, hasOwnProperty()

Trying to access nonexistent properties will always traverse the full prototype chain.

To check whether an object has a property defined on itself and not somewhere on its prototype chain, it is necessary to use the hasOwnProperty() method which all objects inherit from Object.prototype.

hasOwnProperty() is the only thing in JavaScript which deals with properties and does not traverse the prototype chain.



function Graph() {
  this.vertices = [];
  this.edges = [];
}

Graph.prototype = {
  addVertex: function(v) {
    this.vertices.push(v);
  }
};

var g = new Graph();

console.log(g.hasOwnProperty('vertices'));
// true

console.log(g.hasOwnProperty('nope'));
// false

console.log(g.hasOwnProperty('addVertex'));
// false

console.log(g.__proto__.hasOwnProperty('addVertex'));
// true

OOP: Use functions as classes (wcfDeprecated)

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

// Use an array as argument to apply().
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.

Patterns

Proxy Pattern

In the following example, it saves jQuery's setArray-method in a closure and overwrites it. The proxy then logs all calls to the method and delegates the call to the original. Using apply(this, arguments) guarantees that the caller won't be able to notice the difference between the original and the proxied method.



(function() {
  // log all calls to setArray
  var proxied = jQuery.fn.setArray;
  jQuery.fn.setArray = function() {
    console.log( this, arguments );
    return proxied.apply( this, arguments );
  };
})();

Builtin Functions/Objects

developer.mozilla.org: Global Objects.

Value properties

Infinity, NaN, undefined, null

Function properties

isFinite, isNaN

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

parseFloat, parseInt

parseFloat parses its argument, and returns a floating point number. If it encounters a character other than a sign (+ or -), numeral (0-9), a decimal point, or an exponent, it returns the value up to that point and ignores that character and all succeeding characters. Leading and trailing spaces are allowed.

parseInt(string, radix). radix: An integer between 2 and 36 that represents the radix.

If radix is undefined or 0 (or absent): If the input string begins with "0x" or "0X", radix is 16 (hexadecimal); If the input string begins with "0", radix is eight (octal) or 10 (decimal).



//---------- parseFloag

function circumference(r) {
  return parseFloat(r) * 2.0 * Math.PI;
}

console.log(circumference(4.567));
// expected output: 28.695307297889173

console.log(circumference('4.567abcdefgh'));
// expected output: 28.695307297889173

console.log(circumference('abcdefgh'));
// expected output: NaN

//---------- parseInt

function roughScale(x, base) {
  var parsed = parseInt(x, base);
  if (isNaN(parsed)) { return 0 }
  return parsed * 100;
}

console.log(roughScale(' 0xF', 16));
// expected output: 1500

console.log(roughScale('321', 2));
// expected output: 0

encodeURI, decodeURI

encodeURI() encodes a Uniform Resource Identifier (URI) by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character (will only be four escape sequences for characters composed of two "surrogate" characters).



function myFunction() {
    var uri = "my test.asp?%name=ståle&car=saab";
    var enc = encodeURI(uri);
    var dec = decodeURI(enc);
    var res = "Encoded URI: " + enc + "<br>" + "Decoded URI: " + dec;
    document.getElementById("demo").innerHTML = res;
}
// Encoded URI: my%20test.asp?%25name=st%C3%A5le&car=saab
// Decoded URI: my test.asp?%name=ståle&car=saab

var uri = 'https://mozilla.org/?x=шеллы';
var encoded = encodeURI(uri);
console.log(encoded);
// expected output: "https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B"

try {
  console.log(decodeURI(encoded));
  // expected output: "https://mozilla.org/?x=шеллы"
} catch(e) { // catches a malformed URI
  console.error(e);
}

encodeURIComponent, decodeURIComponent



// encodeURIComponent differs from encodeURI as follows:

var set1 = ";,/?:@&=+$";  // Reserved Characters
var set2 = "-_.!~*'()";   // Unescaped Characters
var set3 = "#";           // Number Sign
var set4 = "ABC abc 123"; // Alphanumeric Characters + Space

console.log(encodeURI(set1)); // ;,/?:@&=+$
console.log(encodeURI(set2)); // -_.!~*'()
console.log(encodeURI(set3)); // #
console.log(encodeURI(set4)); // ABC%20abc%20123 (the space gets encoded as %20)

console.log(encodeURIComponent(set1)); // %3B%2C%2F%3F%3A%40%26%3D%2B%24
console.log(encodeURIComponent(set2)); // -_.!~*'()
console.log(encodeURIComponent(set3)); // %23
console.log(encodeURIComponent(set4)); // ABC%20abc%20123 (the space gets encoded as %20)

Numbers and dates

Number

Properties

Number.EPSILON: The smallest interval between two representable numbers.

Number.MAX_SAFE_INTEGER: The maximum safe integer in JavaScript (253 - 1). Number.MIN_SAFE_INTEGER: The minimum safe integer in JavaScript (-(253 - 1)).

Number.NEGATIVE_INFINITY: Special value representing negative infinity; returned on overflow. Number.POSITIVE_INFINITY: Special value representing infinity; returned on overflow.

prototype

Number.prototype.toExponential() Returns a string representing the number in exponential notation. Number.prototype.toFixed() Returns a string representing the number in fixed-point notation. Number.prototype.toString() Returns a string representing the specified object in the specified radix (base). Overrides the Object.prototype.toString() method. Number.prototype.valueOf() Returns the primitive value of the specified object. Overrides the Object.prototype.valueOf() method.

toFixed()


//---------- toFixed

function financial(x) {
  return Number.parseFloat(x).toFixed(2);
}

console.log(financial(123.456));
// expected output: "123.46"

console.log(financial(0.004));
// expected output: "0.00"

console.log(financial('1.23e+5'));
// expected output: "123000.00"

//---------- toExponential

function expo(x, f) {
  return Number.parseFloat(x).toExponential(f);
}

console.log(expo(123456, 2));
// expected output: "1.23e+5"

console.log(expo('123456'));
// expected output: "1.23456e+5"

console.log(expo('oink'));
// expected output: "NaN"

Date

Date objects are based on a time value that is the number of milliseconds since 1 January 1970 UTC.

Date()



var date1 = new Date('December 17, 1995 03:24:00');
// Sun Dec 17 1995 03:24:00 GMT...

var date2 = new Date('1995-12-17T03:24:00');
// Sun Dec 17 1995 03:24:00 GMT...

console.log(date1 === date2);
// expected output: false;

console.log(date1 - date2);
// expected output: 0

//---------- Convert from unix epoch time, e.g. passed from PHP.

// https://stackoverflow.com/questions/847185/convert-a-unix-timestamp-to-time-in-javascript

// Create a new JavaScript Date object based on the timestamp
// multiplied by 1000 so that the argument is in milliseconds, not seconds.
var date = new Date(unix_timestamp*1000);

var hours = date.getHours();
var minutes = "0" + date.getMinutes();
var seconds = "0" + date.getSeconds();

// Will display time in 10:30:23 format
var formattedTime = hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2);

//---------- Several ways to create

var birthday = new Date('December 17, 1995 03:24:00');
var birthday = new Date('1995-12-17T03:24:00');
var birthday = new Date(1995, 11, 17);
var birthday = new Date(1995, 11, 17, 3, 24, 0);

//---------- Calculate the elapsed time

// Method 1: using Date objects
var start = Date.now();
doSomethingForALongTime(); // the event to time goes here.
var end = Date.now();
var elapsed = end - start; // elapsed time in milliseconds

// Method 2: using built-in methods
var start = new Date();
doSomethingForALongTime();
var end = new Date();
var elapsed = end.getTime() - start.getTime(); // elapsed time in milliseconds
format


Date.prototype.toString();
// Returns a string representing the specified Date object. Overrides the Object.prototype.toString() method.

//---------- To print current datetime:
// http://stackabuse.com/how-to-format-dates-in-javascript/
var moment = require('moment');
moment().format();
// '2016-08-02T15:44:09-05:00' // ISO 8601 standard.
moment().format('[The time is] h:mm:ss a');
// 'The time is 4:47:09 pm' 

now(), parse(), UTC()

Date.now()
Returns the numeric value corresponding to the current time - the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC, with leap seconds ignored.

Date.parse()
Parses a string representation of a date and returns the number of milliseconds since 1 January, 1970, 00:00:00, UTC, with leap seconds ignored.
Note: Parsing of strings with Date.parse is strongly discouraged due to browser differences and inconsistencies.

Date.UTC()
Accepts the same parameters as the longest form of the constructor (i.e. 2 to 7) and returns the number of milliseconds since January 1, 1970, 00:00:00 UTC, with leap seconds ignored.

Math

Properties

Math.E
  Euler's constant and the base of natural logarithms, approximately 2.718.
Math.LN2
  Natural logarithm of 2, approximately 0.693.
Math.LN10
  Natural logarithm of 10, approximately 2.303.
Math.LOG2E
  Base 2 logarithm of E, approximately 1.443.
Math.LOG10E
  Base 10 logarithm of E, approximately 0.434.
Math.PI
  Ratio of the circumference of a circle to its diameter, approximately 3.14159.
Math.SQRT1_2
  Square root of 1/2; equivalently, 1 over the square root of 2, approximately 0.707.
Math.SQRT2
  Square root of 2, approximately 1.414.

Methods

Math.abs(x)
Returns the absolute value of a number.
Math.acos(x)
Returns the arccosine of a number.
Math.acosh(x)
Returns the hyperbolic arccosine of a number.
Math.asin(x)
Returns the arcsine of a number.
Math.asinh(x)
Returns the hyperbolic arcsine of a number.
Math.atan(x)
Returns the arctangent of a number.
Math.atanh(x)
Returns the hyperbolic arctangent of a number.
Math.atan2(y, x)
Returns the arctangent of the quotient of its arguments.
Math.cbrt(x)
Returns the cube root of a number.
Math.ceil(x)
Returns the smallest integer greater than or equal to a number.
Math.clz32(x)
Returns the number of leading zeroes of a 32-bit integer.
Math.cos(x)
Returns the cosine of a number.
Math.cosh(x)
Returns the hyperbolic cosine of a number.
Math.exp(x)
Returns Ex, where x is the argument, and E is Euler's constant (2.718…), the base of the natural logarithm.
Math.expm1(x)
Returns subtracting 1 from exp(x).
Math.floor(x)
Returns the largest integer less than or equal to a number.
Math.fround(x)
Returns the nearest single precision float representation of a number.
Math.hypot([x[, y[, …]]])
Returns the square root of the sum of squares of its arguments.
Math.imul(x, y)
Returns the result of a 32-bit integer multiplication.
Math.log(x)
Returns the natural logarithm (loge, also ln) of a number.
Math.log1p(x)
Returns the natural logarithm (loge, also ln) of 1 + x for a number x.
Math.log10(x)
Returns the base 10 logarithm of a number.
Math.log2(x)
Returns the base 2 logarithm of a number.
Math.max([x[, y[, …]]])
Returns the largest of zero or more numbers.
Math.min([x[, y[, …]]])
Returns the smallest of zero or more numbers.
Math.pow(x, y)
Returns base to the exponent power, that is, baseexponent.
Math.random()
Returns a pseudo-random number between 0 and 1.
Math.round(x)
Returns the value of a number rounded to the nearest integer.
Math.sign(x)
Returns the sign of the x, indicating whether x is positive, negative or zero.
Math.sin(x)
Returns the sine of a number.
Math.sinh(x)
Returns the hyperbolic sine of a number.
Math.sqrt(x)
Returns the positive square root of a number.
Math.tan(x)
Returns the tangent of a number.
Math.tanh(x)
Returns the hyperbolic tangent of a number.
Math.toSource() 
Returns the string "Math".
Math.trunc(x)
Returns the integral part of the number x, removing any fractional digits.

Promise

developer.mozilla.org.

A Promise is a proxy for a value not necessarily known when the promise is created. It allows you to associate handlers with an asynchronous action's eventual success value or failure reason. This lets asynchronous methods return values like synchronous methods: instead of immediately returning the final value, the asynchronous method returns a promise to supply the value at some point in the future.

At their most basic, promises are a bit like event listeners except (developers.google.com):

A promise can only succeed or fail once. It cannot succeed or fail twice, neither can it switch from success to failure or vice versa.
If a promise has succeeded or failed and you later add a success/failure callback, the correct callback will be called, even though the event took place earlier.
This is extremely useful for async success/failure, because you're less interested in the exact time something became available, and more interested in reacting to the outcome.


var promise = new Promise(function(resolve, reject) {
  // do a thing, possibly async, then…

  // You can optionally resolve() or reject() with values, which will be passed to the callback functions attached with .then().
  if (/* everything turned out fine */) {
    resolve("Stuff worked!");
  }
  else {
    reject(Error("It broke")); // When reject() with a value, always pass an Error object.
  }
});

// Here's how you use that promise:
// A promise or "thenable" is an object that supplies a standard-compliant .then() method.
promise.then(function(result) {
  console.log(result); // "Stuff worked!"
}, function(err) {
  console.log(err); // Error: "It broke"
});

all()

developer.mozilla.org.

The Promise.all(iterable) method returns a single Promise that resolves when all of the promises in the iterable argument have resolved or when the iterable argument contains no promises.

It rejects with the reason of the first promise that rejects.



var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then(function(values) {
  console.log(values);
});
// expected output: Array [3, 42, "foo"]

Tips

Debug


a = 5;
b = 6;
c = a + b;
console.log(c);

console.log(JSON.stringify(obj));

// https://developer.mozilla.org/en-US/docs/Web/API/Console/log
// console.log prints the element in an HTML-like tree
// console.dir prints the element in a JSON-like tree
// Specifically, console.log gives special treatment to DOM elements, whereas console.dir does not.

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



function component() {
  var element = document.createElement('div');

  // Lodash is required for this line to work
  element.innerHTML = _.join(['Hello', 'webpack'], ' ');

  return element;
}

document.body.appendChild(component());

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

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

History

developer.mozilla.org.



//---------- Traveling through history

window.history.back();
window.history.forward();
// To move back one page (the equivalent of calling back()):
window.history.go(-1);

var numberOfEntries = window.history.length;

//---------- Adding and modifying history entries

// Suppose http://mozilla.org/foo.html executes the following JavaScript:
var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");
// This will cause the URL bar to display http://mozilla.org/bar.html, but won't cause the browser to load bar.html or even check that bar.html exists.

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

Node

EventTarget - Node - Element - HTMLElement

cloneNode()


var dupNode = node.cloneNode([deep]);

The duplicate node returned by cloneNode() is not part of the document until it is added to another node that is part of the document using Node.appendChild() or a similar method. It also has no parent until it is appended to another node.

If deep is set to false, child nodes are not cloned. Any text that the node contains is not cloned either, as it is contained in one or more child Text nodes.

Warning: cloneNode() may lead to duplicate element IDs in a document.

Element

animate()

It's experimental.


document.getElementById("tunnel").animate([
  // keyframes
  { transform: 'translateY(0px)' }, 
  { transform: 'translateY(-300px)' }
], { 
  // timing options
  duration: 1000,
  iterations: Infinity
});

getClientRects()

The Element.getClientRects() method returns a collection of DOMRect objects that indicate the bounding rectangles for each CSS border box in a client.

getElementBy...()

xahlee.info: js get elements.



##### getElementById
var elem = document.getElementById("xyz");
elem.style.color="red"; // change color to red

##### getElementsByTagName
var list = document.getElementsByTagName("p"); // get all p elements
list.length; // show number of items
list[0].style.color = "red"; // make the first one red

##### getElementsByClassName
var list = document.getElementsByClassName("abc");
list[0].style.color = "red"; // make the first one red

##### getElementsByName
// get element by value of the “name” attribute
var xyz = document.getElementsByName("xyz");
xyz[0].style.color="red"; // make the first one red

##### querySelector, querySelectorAll
# Only the first match will be returned
var xx = document.querySelector("span.a, span.c");
# All matched will be returned
var xx = document.querySelectorAll("span.a, span.c");

Change an element

w3schools.



document.getElementsByTagName("INPUT")[0].setAttribute("type", "button");
document.getElementById("myAnchor").setAttribute("href", "https://www.w3schools.com");

var x = document.getElementById("myAnchor");  
if (x.hasAttribute("target")) {       
    x.setAttribute("target", "_self");

document.getElementsByTagName("H1")[0].setAttribute("class", "democlass");

// Bad:
element.setAttribute("style", "background-color: red;");
// Good. Because this will not overwrite other CSS properties that may be specified in the style attribute:
element.style.backgroundColor = "red";
}

// Tip: Use the removeAttribute() method to remove an attribute from an element.

scrollHeight, scrollWidth

Element.scrollHeight is a measurement of the height of an element's content, including content not visible on the screen due to overflow.

The scrollHeight value is equal to the minimum height the element would require in order to fit all the content in the viewport without using a vertical scrollbar. It includes the element's padding, but not its border or margin. It can also include the height of pseudo-elements such as :before or :after.

scrollIntoView()

developer.mozilla.org: scrollIntoView.

Currently, "IE Phone" and "Opera Mobile" doesn't support this. developer.mozilla.org: browser compatibility.



element.scrollIntoView(alignToTop); // Boolean parameter

// If true, the top of the element will be aligned to the top of the visible area of the scrollable ancestor. Corresponds to scrollIntoViewOptions: {block: "start", inline: "nearest"}. This is the default value.
// If false, the bottom of the element will be aligned to the bottom of the visible area of the scrollable ancestor. Corresponds to scrollIntoViewOptions: {block: "end", inline: "nearest"}.

Backup method

stackOverflow: scroll to an element.



window.scroll(0,findPos(document.getElementById("yourSpecificElementId")));

//Finds y value of given object
function findPos(obj) {
    var curtop = 0;
    // HTMLElement.offsetParent returns a reference to the object which is the closest (nearest in the containment hierarchy).
    if (obj.offsetParent) {
        do {
            curtop += obj.offsetTop; // HTMLElement.offsetTop returns the distance of the current element relative to the top of the HTMLElement.offsetParent node. https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetTop
        } while (obj = obj.offsetParent);
    }
    return [curtop];
}

nodeType

w3schools.com.

There are 12 different node types, which may have children of various node types, some of them:

1	Element	Represents an element	Element, Text, Comment, ProcessingInstruction, CDATASection, EntityReference
2	Attr	Represents an attribute	Text, EntityReference
3	Text	Represents textual content in an element or attribute	None
4	CDATASection	Represents a CDATA section in a document (text that will NOT be parsed by a parser)	None
5	EntityReference	Represents an entity reference	Element, ProcessingInstruction, Comment, Text, CDATASection, EntityReference
6	Entity	Represents an entity	Element, ProcessingInstruction, Comment, Text, CDATASection, EntityReference
7	ProcessingInstruction	Represents a processing instruction	None
8	Comment	Represents a comment	None
9	Document	Represents the entire document (the root-node of the DOM tree)	Element, ProcessingInstruction, Comment, DocumentType
10	DocumentType	Provides an interface to the entities defined for the document	None
11	DocumentFragment	Represents a "lightweight" Document object, which can hold a portion of a document	Element, ProcessingInstruction, Comment, Text, CDATASection, EntityReference
12	Notation	Represents a notation declared in the DTD	None


<div id="myDIV">This is a div element.</div>

<script>
var x = document.getElementById("myDIV").firstChild;
var txt = "";
txt += "The node name: " + x.nodeName + "<br>";
txt += "The node value: " + x.nodeValue + "<br>";
txt += "The node type: " + x.nodeType;
</script>

// The result of txt will be:
// 
// The node name: #text
// The node value: This is a div element.
// The node type: 3

HTMLElement

HTMLElements inherit from Element which inherit from Node.

HTMLElement refers explicitly to an HTML element whereas Element may refer to an XML element. However, HTMLElement is technically a subset of Element.

blur(), focus(), click()



focusMethod = function getFocus() {          
  document.getElementById("myText").focus();
}
blurMethod = function getBlur() {          
  document.getElementById("myText").blur();
}

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",
  origin: "http://stackoverflow.com",
  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);

Redirect



// similar behavior as an HTTP redirect
window.location.replace("http://stackoverflow.com");

// similar behavior as clicking on a link
window.location.href = "http://stackoverflow.com";

// IMPORTANT:
// If you want to simulate someone clicking on a link, use  location.href
// If you want to simulate an HTTP redirect, use location.replace

//---------- Relative redirect

window.location.href = '../'; //one level up
window.location.href = '/path'; //relative to domain

Reload/Refresh page

SO.


location.reload();

setInterval/clearInterval, requestAnimationFrame/cancelAnimationFrame


//---------- setInterval

// create a dynamic progress bar:
// https://www.w3schools.com/jsref/met_win_setinterval.asp
function move() {
  var elem = document.getElementById("myBar"); 
  var width = 0;
  var id = setInterval(frame, 10); // Every 10 milliseconds.
  function frame() {
    if (width == 100) {
      clearInterval(id);
    } else {
      width++; 
      elem.style.width = width + '%'; 
    }
  }
}

//---------- Use setInterval for animation

// For the purposes of animation, the goal is sixty "frames" per second to appear smooth, so you'd run a loop like this:

setInterval(function() {
  // animiate something
}, 1000/60);

// Why requestAnimationFrame is better:
// * The browser can optimize it, so animations will be smoother
// * Animations in inactive tabs will stop, allowing the CPU to chill
// * More battery-friendly

//---------- requestAnimationFrame

// https://css-tricks.com/using-requestanimationframe/
var globalID;

function repeatOften() {
  $("<div />").appendTo("body");
  globalID = requestAnimationFrame(repeatOften);
}

// Uncomment the following line will let the progress bar runs auto.
// globalID = requestAnimationFrame(repeatOften);

$("#stop").on("click", function() {
  cancelAnimationFrame(globalID);
});
$("#start").on("click", function() {
  globalID = requestAnimationFrame(repeatOften);
});

setTimeout/clearTimeout

The time value represents the (minimum) delay after which the message will actually be pushed into the queue. If there are messages, the setTimeout message will have to wait for other messages to be processed. For that reason, the second argument indicates a minimum time and not a guaranteed time. developer.mozilla.org: event loop.

A web worker or a cross-origin iframe has its own stack, heap, and message queue. Two distinct runtimes can only communicate through sending messages via the postMessage method. This method adds a message to the other runtime if the latter listens to message events.



(function() {

  console.log('this is the start');

  setTimeout(function cb() {
    console.log('this is a msg from call back');
  });

  console.log('this is just a message');

  setTimeout(function cb1() {
    console.log('this is a msg from call back1');
  }, 0);

  console.log('this is the end');

})();

// "this is the start"
// "this is just a message"
// "this is the end"
// "this is a msg from call back"
// "this is a msg from call back1"


// Display an alert box after 3 seconds (3000 milliseconds):
setTimeout(function(){ alert("Hello"); }, 3000);

// A clock created with timing events
function startTime() {
  var today = new Date();
  var h = today.getHours();
  var m = today.getMinutes();
  var s = today.getSeconds();
  // add a zero in front of numbers<10
  m = checkTime(m);
  s = checkTime(s);
  document.getElementById("txt").innerHTML = h+ ":" + m + ":" + s;
  t = setTimeout(function(){ startTime() }, 500);
}
function checkTime(i) {
  if (i<10) {
    i = "0" + i;
  }
  return i;
}

Events

oninput



<div class="slidecontainer">
  <input type="range" min="1" max="100" value="50" class="slider" id="myRange">
  <p>Value: <span id="demo"></span></p>
</div>

<script>
var slider = document.getElementById("myRange");
var output = document.getElementById("demo");
output.innerHTML = slider.value;

slider.oninput = function() {
  output.innerHTML = this.value;
}
</script>

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;

unload

developer.mozilla.org: unload.

The unload event is fired when the document or a child resource is being unloaded. It is fired after:

The document is in a particular state:

Please note that the unload event also follows the document tree: parent frame unload will happen before child frame unload.

Web API

Event

preventDefault, stopImmediatePropagation, stopPropagation

preventDefault() method tells the user agent that if the event does not get explicitly handled, its default action should not be taken as it normally would be.

stopImmediatePropagation() prevents other listeners of the same event from being called.

stopPropagation() prevents further propagation of the current event in the capturing and bubbling phases.

Event Target

target, currentTarget, relatedTarget, delegateTarget



<div class="elgg-field addButton">
  <div class="elgg-field-input">
    <button id="obj1name" class="elgg-button" type="button">
      <span class="elgg-button-label">新建</span>
    </button>
  </div>
</div>
$('.addButton button').click(selectNew);

// Here comes the result
e.target
<span class=​"elgg-button-label">​新建​</span>​
e.currentTarget
<button id=​"obj1name" class=​"elgg-button" type=​"button">​…​</button>​
e.relatedTarget
null
e.delegateTarget
<button id=​"obj1name" class=​"elgg-button" type=​"button">​…​</button>​

addEventlistener, removeEventListener

developer.mozilla.org: addEventListener.

EventTarget is an interface implemented by objects that can receive events and may have listeners for them.

Element, document, and window are the most common event targets, but other objects can be event targets too, for example XMLHttpRequest, AudioNode, AudioContext, and others.

Many event targets (including elements, documents, and windows) also support setting event handlers via on... properties and attributes.



// You cannot remove a specific anonymous event handler from an object when using the onEVENT syntax. Whenever you call object.onclick =, you overwrite whatever is currently assigned to the onclick property of object.
// You will need to use addEventListener() and removeEventListener() with a named function:

function windowClicker(event) 
{
    if (event.target == modal) 
    {
        modal.style.display = "none";
    }
}

// Add the listener:
window.addEventListener('click', windowClicker, false);

// Remove it:
window.removeEventListener('click', windowClicker, false);

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>