An Introduction to Modern JavaScript

Ben Aston
5 min readApr 13, 2015

“If we understand others, in time, I believe, we come to understand ourselves.” John Koenig, Space 1999

The little language you love to hate has come a long way since its creation in 1995.

Here I share examples of modern JavaScript to both inform and to challenge preconceptions.

Partial Application

This functional technique binds argument values to a function for later use. Partial application has been possible in JavaScript since the 1990s, but modern syntax makes it easier to follow.

Example

function partial(fn, ...bound) {
if (!bound.length) {
return fn;
}
return function(...args) {
return fn.apply(this, bound.concat(args));
};
}

Use

function foo(...args) { 
console.log(args);
}
foo = partial(foo, 1, 2); // Partially apply the function.foo('3'); // [ 1, 2, '3' ]

If you would like to use partial application in your ES3 or ES5 app you can experiment with Function.prototype.bind. Alternatively, you might like to try partial-application on NPM.

Mixins

Classical inheritance has its downsides. It tightly couples parent and child, plus multiple inheritance gets complicated fast.

Mixins are an alternative where the properties of one object are simply copied onto another. Object.assign makes the job significantly easier in ES6.

Example

function mix(fn, ...mixers) {
return Object.assign(fn.prototype,
...mixers.map(m => m.prototype));
}

Use

function foo() {}
foo.prototype.foo = 'foo';
function bar() {}
bar.prototype.bar = 'bar';
function foobar() {}
mix(foobar, foo, bar);
Object.keys(foobar.prototype); // [ 'foo', 'bar' ]

If you would like a trivial library to help you mix functions together in your ES3 or ES5 code, try mixx on NPM.

Classes

Classical object orientation remains a popular way of organizing code. JavaScript now has syntax to emulate this pattern, although under the hood, it remains fundamentally different to languages such as C++, Java and C#.

Example

class Car extends Vehicle {
constructor(color) {
this.color = color;
}

changeGear() {
//...
}
}

Use

var myCar = new Car('silver');
myCar.color; // 'silver'
myCar.changeGear();
myCar instanceof Vehicle; // true

Objects

JavaScript also supports purely object-based programming. This is arguably closer to the original philosophy behind the language.

Many of the “good parts” of JavaScript can be found in this area, including:

— the ease with which functions and objects can be created

— objects as dictionaries (aka maps or hashes) with dynamic properties

— functions as objects

Example 1

The humble no-op. This example demonstrates the ability to add properties to functions, resulting in a terse and meaningful API.

function noop() {}noop.truthy = ()=> true; // Functions can have properties.
noop.falsy = ()=> false;

Use

noop(); // undefined
noop.truthy(); // true

Example 2

ES6 introduces shorthands for working with object literals.

The following example demonstrates the new convention of configuring the prototype chain for an object literal, the new abbreviation for property setting and the use of expressions to create calculated property names.

var bmw = {
marque: 'BMW'
};
var color = 'silver';
var myCar = {
__proto__: bmw,
color,
['prop' + (()=> 42)()]: 42,
toString() {
return `A ${this.color} ${super.marque}.`;
}
};

Use

myCar.color; // 'silver'
myCar instanceof bmw // true
myCar.prop42 // 42
myCar.toString(); // 'A silver BMW.'

Array Methods

Take a look at the following problem and its solution. A solution in another modern language, Scala, is supplied for comparison.

“Write a function that, given a string, produces a map of the indexes of all characters.

For example, indexes(“Mississippi”) should return a map associating ‘M’ with the set {0}, ‘i’ with the set {1, 4, 7, 10}, and so on.”

function indexes(s) {
return s.split('').reduce((p, c, i) => {
if (!p[c]) {
p[c] = [i];
} else {
p[c].push(i);
}
return p;
}, {});
}

Use

indexes(‘Mississippi’); // { M: Array[1], i: Array[4], s: Array[4], p: Array[2] }

Example

…and a Scala implementation. Corrections welcome! I am not a Scala developer...

def index(s1: String): Map[Char, Set[Int]] = {
@tailrec def index(cache: Map[Char, Set[Int]], s2: String, pos: Int): Map[Char, Set[Int]] = {
val indexSet = cache.getOrElse(s2.head, Set[Int]()) + pos
val updatedCache = cache + (s2.head -> indexSet)
if (s2.tail.nonEmpty)
index(updatedCache, s2.tail, pos + 1)
else
updatedCache
}
index(Map(), s1, 0)
}

Use

index("Mississippi").foreach { case (k, v) => println(k + " " + v) }

Continuations / Generators

One of my favorite features of ES6. Generators enable coroutine-like behavior in your JavaScript applications. Generators can also be used to model infinite sequences.

Example

The following implementation of the classic Comp. Sci. 101 fibonacci number generator is both highly readable and terse.

It also makes use of the destructuring assignment feature of ES6 to avoid the need for an explicit temporary variable.

function* fib() {
var prev, curr;

yield 0;
yield prev = curr = 1;
while(1) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}

Use

var gen = fib();gen.next().value; // 0
gen.next().value; // 1
gen.next().value; // 1
gen.next().value; // 2
gen.next().value; // 3
gen.next().value; // 5

Promises

Promises are an evolution of our understanding of the modelling of temporal values. Promises represent future values not yet available.

ES6 makes them native.

function timeout(duration = 0) {
return new Promise((resolve, reject) =>
setTimeout(resolve, duration));
}

The above is based on the example at MDN.

Use

timeout(1000)
.then(()=> console.log('a'))
.then(()=> timeout(2000))
.then(()=> console.log('b'))
.then(()=> { throw new Error('hmm'); })
.catch(err => Promise.all([
timeout(100),
console.log(`err: ${err}`)
]));

Modularization

The lack of built-in modularization support in JavaScript has spawned a dozen different approaches, all of which us function scoping to achieve their end.

ES6 brings native modularization capability, including asynchronous module loading.

Example

// lib/foobar.js
export function foo() {
//…
}
export var bar = 0;

Adapted from the example at MDN.

Use

// app.js
import * as foobar from ‘lib/foobar’;
alert(`${foobar.foo}, ${foobar.bar}`);
// otherApp.js
import {foo, bar} from ‘lib/foobar’;
alert(`${foo}, ${bar}`);

Tail-call Optimisation

With ES6, JavaScript graduates to be a full-fledged functional language. Tail call optimizations mean that certain kinds of recursion will no longer be limited by the call stack. You don’t even need looping constructs anymore!

The following code sums the values supplied to it.

Example

The seemingly redundant inner function here is used to make the recursive call eligible for tail call optimization.

function sum(...values) {
return (function sumArr(acc, values) {
if(!values.length) {
return acc;
}
return sumArr(acc + values.shift(), values);
}(0, values));
}

Use

sum(1, 2, 3); // 6

Summary

I would argue JavaScript has been a serious programming language since 1999 and ES3, but the perception has not always matched that reality.

Hopefully, the examples presented here will help those coming from other programming language communities understand JavaScript a little better, and perhaps in so doing, themselves.

My name is Ben Aston and thank you for reading my post today. I am a London-based JavaScript consultant, available for short-term consultancy globally. I can be contacted at ben@bj.ma.

If you would like to further develop your knowledge of JavaScript you might be interested in my hands-on training course. Full details can be found online at www.learnjavascript.london.

If you enjoyed this piece, please let me know by clicking the “recommend” button below.

You may also be interested in my post on closures in JavaScript.

Made in the United Kingdom

--

--