JavaScript Language Evolution: Core Features from ES2015 to ES2019
ES2015 (ES6) Enhancements
Class Syntax
ES2015 introduced syntactic sugar over JavaScript's prototype-based inheritance, enabling cleener object-oriented patterns.
class Vehicle {
constructor(model, year) {
this.model = model;
this.year = year;
}
displayInfo() {
console.log(`${this.year} ${this.model}`);
}
}
class ElectricCar extends Vehicle {
constructor(model, year, range) {
super(model, year);
this.range = range;
}
displayInfo() {
super.displayInfo();
console.log(`Range: ${this.range} miles`);
}
}
const car = new ElectricCar('Model S', 2023, 400);
car.displayInfo();
Module System
The standardized module system uses export and import for dependency management.
// mathUtils.js
export const PI = 3.14159;
export function calculateCircumference(radius) {
return 2 * PI * radius;
}
// main.js
import { PI, calculateCircumference } from './mathUtils.js';
Arrow Functions
Lexical scoping of this eliminates the need for explicit binding in callbacks.
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(n => n * 2);
// Lexical this binding
const counter = {
value: 0,
increment: function() {
setInterval(() => {
this.value++;
console.log(this.value);
}, 1000);
}
};
Default Parameters
Function parameters can specify fallback values directly in the signature.
function createUser(username = 'guest', role = 'viewer') {
return { username, role };
}
// Prevents falsy value bugs
function multiply(a, b = 1) {
return a * b;
}
multiply(5, 0); // Returns 0, not 5
Template Literals
Interpolated strings support embedded expressions and multi-line content.
const user = { first: 'Jane', last: 'Doe' };
const greeting = `Welcome, ${user.first} ${user.last}!`;
const html = `
<div>
<h1>${greeting}</h1>
</div>
`;
Destructuring Assignment
Extract values from arrays and objects into distinct variables.
// Array destructuring
const coords = [10, 20, 30];
const [x, y, z] = coords;
// Object destructuring
const product = { id: 101, name: 'Laptop', price: 999 };
const { name, price } = product;
// Nested destructuring
const response = { data: { user: { email: 'test@example.com' } } };
const { data: { user: { email } } } = response;
Spread Syntax
Expand iterable elements or object properties into individual elements.
// Array spreading
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5, 6];
// Object spreading
const defaults = { theme: 'dark', fontSize: 14 };
const settings = { ...defaults, fontSize: 16 };
// Function arguments
function sum(a, b, c) {
return a + b + c;
}
const values = [1, 2, 3];
sum(...values);
Property Shorthand
Object literals infer property names from variable identifiers.
const latitude = 40.7128;
const longitude = -74.0060;
const location = { latitude, longitude };
// Equivalent to: { latitude: latitude, longitude: longitude }
Promise Objects
Native asynchronous programming abstraction replacing callback patterns.
function fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then(response => response.json())
.then(data => resolve(data))
.catch(error => reject(error));
});
}
fetchData('/api/user')
.then(user => console.log(user))
.catch(err => console.error(err));
Block-Scoped Declarations
let and const provide lexical scoping within blocks, unlike function-scoped var.
if (true) {
let blockScoped = 'visible only here';
const constant = 'cannot reassign';
}
// blockScoped and constant are not accessible here
ES2016 (ES7) Additions
Array.prototype.includes()
Determines array membership with a boolean return value.
const fruits = ['apple', 'banana', 'cherry'];
const hasApple = fruits.includes('apple'); // true
const index = fruits.indexOf('apple'); // 0
Exponentiation Operator
Mathematical power operator as an alternative to Math.pow().
const cubed = 3 ** 3; // 27
const square = Math.pow(4, 2); // 16
ES2017 (ES8) Features
Async Functions
Syntactic sugar for Promise-based asynchronous operations.
async function getUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
const user = await response.json();
return user;
} catch (error) {
console.error('Fetch failed:', error);
}
}
Object Value Extraction
Object.values() returns enumerable property values.
const config = { host: 'localhost', port: 3000, ssl: true };
const values = Object.values(config); // ['localhost', 3000, true]
Object Entry Iteration
Object.entries() returns key-value pairs for iteration.
const scores = { math: 95, science: 88, english: 92 };
for (const [subject, score] of Object.entries(scores)) {
console.log(`${subject}: ${score}`);
}
String Padding
padStart() and padEnd() normalize string lengths.
const invoice = '42';
const padded = invoice.padStart(6, '0'); // '000042'
const description = 'Item';
const aligned = description.padEnd(10, '.'); // 'Item......'
Trailing Commas
Function parameter lists and calls tolerate trailing commas.
function setup(
host,
port,
protocol, // Trailing comma allowed
) {
// Implementation
}
Property Descriptors
Object.getOwnPropertyDescriptors() retrieves all property descriptors.
const target = {
name: 'example',
get value() { return 42; }
};
const descriptors = Object.getOwnPropertyDescriptors(target);
Shared Memory Operations
SharedArrayBuffer and Atomics enable concurrent memory access patterns.
const buffer = new SharedArrayBuffer(1024);
const view = new Int32Array(buffer);
Atomics.store(view, 0, 123);
const value = Atomics.load(view, 0);
ES2018 (ES9) Capabilities
Asynchronous Iteration
for-await-of loops handle asynchronous iterators.
async function* asyncGenerator() {
yield await Promise.resolve(1);
yield await Promise.resolve(2);
}
(async () => {
for await (const num of asyncGenerator()) {
console.log(num);
}
})();
Promise Completion Handling
finally() executes cleanup logic regardless of settlement state.
fetch('/api/data')
.then(response => response.json())
.catch(error => console.error(error))
.finally(() => {
console.log('Request completed');
});
Rest and Spread for Objects
Destructuring and spreading work with object properties.
const { id, ...metadata } = { id: 1, name: 'Doc', size: '2MB' };
const merged = { ...metadata, timestamp: Date.now() };
Regular Expression Enhancements
Named Capture Groups:
const datePattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = datePattern.exec('2023-12-25');
console.log(match.groups.year); // '2023'
Lookbehind Assertions:
const pricePattern = /(?<=\$)\d+\.?\d*/;
const price = pricePattern.exec('Price: $49.99')[0]; // '49.99'
DotAll Flag:
const multiline = /hello.world/s;
multiline.test('hello\nworld'); // true
Unicode Property Escapes:
const greekLetter = /\p{Script=Greek}/u;
greekLetter.test('Ω'); // true
ES2019 (ES10) Improvements
Array Flattening
flat() collapses nested arrays; flatMap() maps then flattens.
const nested = [1, [2, 3], [4, [5, 6]]];
const flattened = nested.flat(2); // [1, 2, 3, 4, 5, 6]
const sentences = ['Hello world', 'Goodbye moon'];
const words = sentences.flatMap(s => s.split(' '));
String Trimming
trimStart() and trimEnd() remove whitespace from specific ends.
const input = ' padded ';
const leftTrimmed = input.trimStart(); // 'padded '
const rightTrimmed = input.trimEnd(); // ' padded'
Object from Entries
Convert key-value pairs into objects, inverting Object.entries().
const pairs = [['x', 10], ['y', 20]];
const point = Object.fromEntries(pairs); // { x: 10, y: 20 }
const map = new Map([['a', 1], ['b', 2]]);
const obj = Object.fromEntries(map);
Symbol Descriptions
Access symbol descriptions via the description property.
const sym = Symbol('unique identifier');
console.log(sym.description); // 'unique identifier'
Match All Iterations
matchAll() returns an iterator of all matches including capture groups.
const text = 'test1test2';
const regex = /t(e)(st(\d?))/g;
const matches = [...text.matchAll(regex)];
// Access individual capture groups per match
Function Source Preservation
toString() returns exact source code including comments and whitespace.
function /* note */ example() {}
console.log(example.toString());
// Includes comment in output
Optional Catch Binding
Omit error parameter when exception details are unnecessary.
try {
riskyOperation();
} catch {
handleErrorGenerically();
}
BigInt Type
Arbitrary-precision integers beyond Number.MAX_SAFE_INTEGER.
const huge = 9007199254740993n;
const result = huge + 1n;
console.log(result === 9007199254740994n); // true
Global This
Universal global object reference acros environments.
const globalObject = globalThis;
// Works in browsers, Node.js, and web workers
Dynamic Imports
Programmatic module loading returning promises.
async function loadModule() {
const { utility } = await import('./utils.js');
utility();
}