Why is it called ECMAScript?

Most popular baby names of 1995

Boy Girl
Michael Jessica
Matthew Ashley
Christopher Emily
Jacob Samantha
Joshua Sarah
Programming
Java
C
C++
VisualBasic
Perl

What's in a name?

Mocha

LiveScript

JavaScript

ECMAScript

ECMAScript Timeline

ES1

1997

ES2

1998

ES3

1998

ES5

2009

ES5.1

2011

ES2015

ES2016 

ES2017

ES2018

ES2019

Note: timeline is not to scale. Don't be pedantic.

How does a feature get into ECMAScript?

  • Stage 0: Strawman
  • Stage 1: ​​Proposal
  • Stage 2: Draft
  • Stage 3: Candidate
  • Stage 4: Finished

What has reached Stage 4?

  • Optional Catch Binding

  • Subsume JSON

  • Symbol Description Accessor

  • Function “toString” Revision

Optional Catch Binding

function isValidJSON(text) {
  try {
    JSON.parse(text);
    return true;
  } catch(unusedVariable) {
    return false;
  }
}
function isValidJSON(text) {
  try {
    JSON.parse(text);
    return true;
  } catch {
    return false;
  }
}

Subsume JSON

JSON strings accept the unescaped line separator (U+2028) and unescaped paragraph separator (U+2029) characters while ECMAScript strings do not.

As of ES2019, ECMAScript will be extended to support these characters in strings to smooth out any inconsistencies in various implementations.

Symbol Description Accessor

const symbol = 
  Symbol('My Symbol'); 

console.log(symbol.toString()); 

// Symbol(My Symbol)
const symbol = 
  Symbol('My Symbol'); 

console.log(symbol.description);
// My Symbol

Function “toString” Revision

function () { console.log('foobar'); }.toString());

Dependent on the engine it either returned a string with the code of the function or threw a syntax error.

In ES2019 it will return:

  1. a string of the code

  2. NativeFunction

  3. GeneratorFunction

  4. or throw a Type Error

What about Stage 3?

  • globalThis

  • import()

  • Legacy RegExp features in JavaScript

  • BigInt

  • import.meta

  • Private instance methods and accessors

  • Array.prototype.{flatMap,flat}

  • Hashbang Grammar

  • Class Public Instance Fields & Private Instance Fields

  • Static class fields and private static methods

  • String.prototype.{trimStart,trimEnd}

  • String.prototype.matchAll

  • Object.fromEntries

  • Well-formed JSON.stringify

import()

<!DOCTYPE html>
<nav>
  <a href="books.html" data-entry-module="books">Books</a>
  <a href="movies.html" data-entry-module="movies">Movies</a>
  <a href="video-games.html" data-entry-module="video-games">Video Games</a>
</nav>

<main>Content will load here!</main>

<script>
  const main = document.querySelector("main");
  for (const link of document.querySelectorAll("nav > a")) {
    link.addEventListener("click", e => {
      e.preventDefault();

      import(`./section-modules/${link.dataset.entryModule}.js`)
        .then(module => {
          module.loadPageInto(main);
        })
        .catch(err => {
          main.textContent = err.message;
        });
    });
  }
</script>

Private instance methods and accessors

class Counter extends HTMLElement {
  #xValue = 0;

  get #x() { return #xValue; }
  set #x(value) {
    this.#xValue = value; 
    window.requestAnimationFrame(this.#render.bind(this));
  }

  #clicked() {
    this.#x++;
  }

  constructor() {
    super();
    this.onclick = this.#clicked.bind(this);
  }

  connectedCallback() { this.#render(); }

  #render() {
    this.textContent = this.#x.toString();
  }
}
window.customElements.define('num-counter', Counter);

Static Class Fields

class CustomDate {
  // ...
}
CustomDate.epoch = 
  new CustomDate(0);
class CustomDate {
  // ...
  static epoch = 
    new CustomDate(0);
}

Static Private Methods and Fields

class ColorFinder {
  static #red = "#ff0000";
  static #blue = "#00ff00";
  static #green = "#0000ff";
  #colorValue = ColorFinder.#red;
  
  static #colorName(name) {
    switch (name) {
      case "red": return ColorFinder.#red;
      case "blue": return ColorFinder.#blue;
      case "green": return ColorFinder.#green;
      default: throw new RangeError("unknown color");
    }
  }
  
  getColor() { 
    return ColorFinder.#colorName(#colorValue);
  }
}

trimStart/trimEnd

let foo = "   abcdef   ";

foo.trimStart();
// "abcdef   "

foo.trimEnd();
// "   abcdef"

Implementations:

  • V8, in Chrome 66+
  • SpiderMonkey, in Firefox 61+
  • JSC, in Safari 12+
  • ChakraCore

The End…

…For Now