Stuff about programming
JavaScript quick reference.
Bookmark and Share

Notes on JS features from ES5 to ES6 and some ES3. Note that there was no ES4.

Semi colons

Semi colons are optional. Gotchas to watch out for: return 1; returns undefined because of the line break. var f = () => ({x:2}) f ({x:1}).x evaluates to 2. I prefer to omit semi-colons.

Object creation

Literal - prototype defaults to Object: {}.

Function constructor - prototype defaults to Object if not set. function F() { this.prototype = ...} new F() or set the prototype as F.prototype = ...

ES5 creation: Object.create(prototype, propertyDescriptors). When prototype is null then the new object's prototype is undefined.

Equals

== performs a type conversion. === is stricter and returns false for all pairs of values that have different types.

Object methods

valueOf is used in string conversions i.e. '' + x is like x.valueOf().toString(). toString defaults to [object classname] where classname is an internal property of the runtime but can be used to extract the class of an object e.g. Object.prototype.toString.call(o). toJson is used when serialising an object to a string e.g. JSON.stringify(v) is like JSON.stringify(v.toJson()) and defaults to identity. call invokes a function with a specific binding to this and remaining arguments. apply is like call but takes its arguments as an array. e.g. useful to flatten an array of arrays: Array.prototype.concat.apply([], [[1,2], [3,4]]) returns [1,2,3,4]. bind returns a new function with partially applied arguments. Its first argument is this and is a bit like currying in functional programming. Check if x is NaN: x != x. or isNaN(x). In ES5: Object.is(x, NaN).

Object properties

An object is a dynamic set of key/value properties with unique keys. Set a property p on o to value v: o.p = v or o[p] = v. JS values are either objects, values of primitive type (numbers, strings, boolean), or functions - if the latter then it is a method of o. In ES5, an object's enumerable key/value pairs is returned in an array of arrays by Object.entries(o). Object.getOwnPropertyNames(o) returns an array of all own properties including those with enumerable set to false. Object.keys should be called getOwnEnumerableKeys.

Types

The JS primitive types are: number, string, boolean. All non-primitive objects have type: object. The type of undefined is undefined. The type of null is object.

Arrays

An array is created as a literal [] or with new Array(). An array-like object has a length property and enumerable numeric keys >= 0 and <= Infinity. Such an object can be handled as an array but won't offer random access times expected from a real array. Array methods push, pop, shift, unshift maintain the length property. An array like object can be converted to an array using: Array.prototype.slice.call({0:1, 1:2,length:2}) A sparse array literal with commas is filled with undefined values: [,,,] Return a new subarray : array.slice(start, end). array.slice(start) slices to the end. array.slice() copies the array. Alter an array in-place : array.splice(start (, numberDeletions (,newElements)*)+). ES5 additions: filter, map, reduce, some, every. ES6 - find first occurance of element matching a predicate find(p), findIndex(p).

Inheritance

JS has prototype based inheritence. An object's prototype can be accessed in ES5 with: Object.getPrototypeOf(o) or through nonstandard properties such as __prototype__. This property is set by the runtime as defined above during object creation. A property access on an object traverses its prototype chain returning the first matching property. An overriden property overshadows any property with the same name in the prototype chain. Adding or removing a property on the prototype (which may be shared with many objects) affects all the objects which inherit from the prototype.

this

this is a keyword in a function scope, not a variable. Its value is dynamic and depends on the invocation context and whether strict mode is enabled. In an object function constructor - this refers to the newly created object. In a top level function this refers to the global object in non strict mode or is undefined in strict mode. In a method - this refers to the object on which the method is a property. Since this is not a variable - it is not captured by a closure and must be assigned to a new variable e.g self - in order to be captured.

arguments

arguments is a keyword inside a function body that represents an array-like object for the function arguments.

Property access control in ES5.

A property's descriptor has 3 boolean valued attributes for access control: writable - is it not readonly? An object with a get method and without a set method is readonly by default. enumerable - is the property returned by Object.keys and iterable in a for loop? configurable - can it be deleted? Object.preventExtensions(o) prevents new properties being added to o. Object.seal() is as preventExtensions, but also prevents property deletion and further configuration. Properties are still writable. Object.freeze(o) is as seal, but also makes all properties read only. These can be tested with Object.isExtensible, Object.isSealed and Object.isFrozen. Properties are configured with: Object.defineProperty and Object.defineProperties. The first takes an object to extend, a property name and a descriptor definition: { writable: boolean, configurable: boolean, enumerable: boolean, value: any, get: void => any, set: any => void } The latter takes its descriptor config as an object with each property key mapped to a descriptor definition. An own property descriptor is retrieved with Object.getOwnPropertyDescriptor()

Property membership testing.

'propertyName' in o - does o have an own or inhertited property? o.hasOwnProperty('propertyName') - does o have an own property? o.propetyIsEnumerable('propertyName') - is the property returned in Object.keys and iterable in a for of loop? o.p !== undefined - o may or not have a property p.

Scope

ES3 has function scope, not block scope. Furthermore, variable declarations are "hoisted" to the top of a scope. i.e. if a variable is used before it is declared then that's okay! Each function scope introduces a new scope on the stack with normal shadowing rules. ES6 introduced familiar block scope through let bindings. e.g. let( x = v) { ... }

Creating a final object in ES5?

Set a null prototype and freeze all properties - perhaps something like this: Object.freeze(Object.assign(Object.create(null), {x:1}))

Promise (ES6).

A promise is a monad like object for writing asynchronous code that avoids callback hell. Its constructor takes a higher order function (called an executor) with function parameters resolve, reject and error. e.g. this code starts running a new promise that resolves to a string value after 0.5 seconds. new Promise(resolve => { setTimeout(() => resolve('timed out!'), 500) }) We can capture the timeout event and its resolved value with a callback on the promise: new Promise(resolve => { setTimeout(() => resolve('timed out!'), 500) }).then (console.log) Exceptions thrown during the evaluation of the promise or rejections, can be caught with the catch callback: new Promise(resolve => { setTimeout(() => resolve('timed out!'), 500) }).then (console.log) .catch (console.error) Recall that the monad's bind function looks like this Ma -> a -> Mb -> Mb The Promise.then method follows this pattern, which has type a -> Mb -> Mb as it may return a new Promise that resolves to a new value. This is called a chain of promises. Promise.all takes a list of promises which resolves when all promises resolve in parallel. Promise.resolve returns a promise that is immediately resolved.

Closures.

When an expression such as a function or object flows out of its current scope such as being returned from or passed to a function, then its free variables are closed under the lexical scope (i.e. the syntactic position of the expression). Free variables are the variables in an expression that are not bound variables, i.e. the variables that appear in a function's list of formal parameters. this inside an ES6 Fat arrow function is bound at the point of declaration and cannot be changed - contrasting with an ES3 function declaration.

Iterable protocol (ES6).

An object can appear in a for of loop when it implements the iterable protocol: let c = { [Symbol.iterable]() { let start = 0 return { next() { return { value: start++, done: start > 10 } } } } } for (let i of c) console.log(i) logs 0 to 9.

Generators (ES6).

A generator function yields many values: function * values() { yield 1 yield * [2,3,4] } and can be used in a for of statement: for (let v of values()) console.log(v) logs 1 2 3 and 4. A class method generator: class C { * values() { } } Object literal method generator: { * values() { } } A generator implements the iterable protocol: let g = values() g.next() // {value: 1, done: false} g.next() // {value: 2, done: false} The consumer can feedback to the generator by passing a value to next: g.next('hi') and inside the generator this value is picked up: let message = yield console.log(message) // hi Generators are used to model asynchronous control flow without callbacks. Note that the generator yields control to the consumer and is resumed when the consumer calls next on the generator. So the idea is for the generator to yield a promise, which when resolved, the consumer passes the resolved value back to the generator with next - relinquishing control to the generator with the result. So the generator is where you may wait on an asynchronous value without blocking. The consumer in this case is just a utility method that captures the promises' happy path. e.g. using whatwg fetch: function async(promiseIterator) { let promises = promiseIterator() let consume = lastResolvedValue => { let promise = promises.next(lastResolvedValue) if (!promise.done) { promise.value.then(consume) } } consume() } async(function* () { let data = yield fetch('/') data.text().then(console.log) })

Global object.

window is the global object on client side JS.

Strict mode.

A single line at the start of a function body or block: 'use strict'; enables strict mode. This will e.g. enable more ReferenceErrors and TypeErrors at runtime and disallow constructs such as with expressions. this inside a function body is never bound to the global object in strict mode.

Proxies (ES6) Classes (ES6) Modules (ES6) Other favourite ES6 features.

Property shorthand notation: {a,b}.

Computed properties: {[e]:v}.

Spread operators for arrays and objects: [...a, ...b] and {...a, ...b}. The latter is like Object.assign({}, a, b) in ES5.

Assignment destructuring for arrays: [a1,a2, ...as] = array and for objects: {p1,p2} = o.

Deep matching: {a:{b}} = o.

Default arguments: function(x = {}){}.

Matching arguments: function({a,b}){}.

String literals (interpolation): `Hello ${name}!`.

Multiline strings: `Hello ${name}! `

blog comments powered by Disqus
Website created by Nicholas Nguyen.