All notes
Javascrip

Intro

Good references

Reference.

Concepts

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

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.

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

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

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

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.

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
}

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

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

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

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

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

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



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

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

Getter, Setter



{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

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: Use functions as classes

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

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


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

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

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


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

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

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

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


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

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

Constructor

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


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

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

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

Shared methods defined through "prototype"

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

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


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

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


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

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

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


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

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

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


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

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

s.reversed(); // nomiS

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

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


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

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

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

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


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

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

Calling


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

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


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

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

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

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

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

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

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

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

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

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

call, apply, bind

zhihu.


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

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

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

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.

eval

SO.


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

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

Tips

Debug


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

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

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.

Window Navigator

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

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

getElement

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

Element

animate()

It's experimental.


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

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

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.

JS BOM

Browser Object Model (BOM).

JS window

Location

w3school.

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

Refulz.

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

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

GetURL.


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

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

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

Events

window.onload, document.onload

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


<!DOCTYPE html>
<html>
<body>

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

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

</body>
</html>

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

window.onload = showPic;

FAQ

Display XML

mozilla developer.


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

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

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

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

How to make async JS load in order?

Use "defer" instead of "async".

gfw.js


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

Speed Boost

Normal

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

window.load event

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


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

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

Async, Defer

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


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