ECMAScript — стандарт, на котором основан JavaScript, его часто называют ES.

ES3, ES5, ES6, ES7, ES8, ES2015, ES2016, ES2017, ES2018, ES2019, ECMAScript 2015, ECMAScript 2016, ECMAScript 2017, ECMAScript 2018, ECMAScript 2019 — как разобраться во всем этом?
ECMAScript (/ˈɛkməskrɪpt/) (или ES) является языком программирования общего назначения , стандартизирован ассоциацией Ecma International согласно документу ECMA-262 . Это стандарт JavaScript, предназначенный для обеспечения взаимодействия веб-страниц в разных веб-браузерах.
Историческая справка
Ecma International — основанная в 1961 году ассоциация, деятельность которой посвящена стандартизации информационных и коммуникационных технологий. Изначально ассоциация называлась ECMA — European Computer Manufacturers Association, однако она сменила название в 1994 году в связи с глобализацией деятельности. Вследствие этого название Ecma перестало быть аббревиатурой и больше не пишется заглавными буквами.
Когда JavaScript был создан, он был представлен Netscape и Sun Microsystems для Ecma, и они дали ему имя ECMA-262 (псевдоним ECMAScript).
До ES2015 спецификации ECMAScript обычно назывались их редакцией. Таким образом, ES5 является официальным названием обновления спецификации ECMAScript, опубликованной в 2009 году.
В процессе разработки ES2015, название было изменено с ES6 на ES2015, но мир всё еще называет релизы ES номером издания.
Также комитетом было принято решение о ежегодном пересмотре и выпуске стандарта, в результате, начиная с 2015 года, мы каждый год получаем новый стандарт ECMAScript.
Для лучшего понимания исторической последовательности развития стандартов JavaScript смотрите табличку ниже:

ECMAScript2015 (ES6)
ES5 разрабатывался 10 лет, с 1999 по 2009 год и был полон существенных изменений, поэтому он считает фундаментальной версией стандарта ECMAScript.
Стрелочные функции
let func = (arg1, arg2, arg3) => expressionБолее интуитивное управление текущим контекстом объекта
thisОбъявление переменных с помощью
letиconstПромисы (Promises)
const waitFunc = () => 
  new Promise((resolve, reject) => { 
    setTimeout(resolve, 1000);  
  });
waitFunc().then(() => {    
  console.log("I promised to run after 1s");  
});
Генераторы (Generators)— это особый тип функций, которые могут приостанавливать своё выполнение, возвращать промежуточный результат и далее возобновлять его позже, в произвольный момент времени, что позволяет запускать другой код в момент приостановления функции. Для объявления генератора используется синтаксическая конструкция:
function*(функция со звёздочкой).Шаблонные литералы (Template Literals) — это новый синтаксис для создания строк, обеспечивающий способ встраивания выражений в строки, используя синтаксис
${имя_переменной}:
const name = "Irina";
const string = `Hey ${name}`; // Hey Irina
Параметры по умолчанию в функциях:
const sayMyName = function (name = "Irina") {  
  console.log(name);
};
sayMyName(); // Irina
Spread/Rest синтаксис (
...) в параметрах функций:
// spread
Math.max(...[2,100,1,6,43]) // 100
// rest
function print(format, ...params) {     
  console.log('params: ', params);     
  console.log('format: ', format); 
}  
print('hello', 'adrian', 321, Math.PI);
Деструктуризация (Destructuring Assignment) — синтаксис, позволяющий извлекать данные из массивов и объектов.
const user = {firstName: 'Adrian', lastName: 'Mejia'};  
function getFullName({ firstName, lastName }) {      
  return `${firstName} ${lastName}`; 
} 
console.log(getFullName(user));
Symbol — это уникальный и неизменяемый тип данных, который может быть использован как идентификатор для свойств объектов.
var sym1 = Symbol();
var sym2 = Symbol("foo");
Symbol("foo") === Symbol("foo"); // false
Цикл
for...ofвыполняет цикл обхода любых итерируемых объектов (включаяArray,Map,Set, объект аргументов и т.д.), и имеет возможность разрываbreak;
Итерируемым объектом является любой объект, который реализует интерфейс Iterable, то есть у которого есть метод Symbol.iterator, возвращающий объект с методом next().
MapиSet(и их соответствующие аналоги WeakMap и WeakSet с поддержкой сборки мусора) — являются официальными реализациями двух очень популярных структур данных:
Map содержит пары ключ-значение и сохраняет порядок вставки. Любое значение может быть использовано в качестве ключа.
Set позволяет сохранять уникальные значения любого типа.
Классы:
Конструктор — специальный метод
constructor, который вызывается, когда класс инициализируются с помощьюnew. Родительскийconstructorнаследуется автоматически, если у потомка нет своего методаconstructor. Если же потомок имеет свойconstructor, то, чтобы унаследовать конструктор родителя нужно использоватьsuper()с аргументами для родителя.super()— используется для вызова функций, принадлежащих родителю объекта;Getters and setters:
get связывает свойство объекта с функцией, которая вызывается при обращении к этому свойству
class Person {  
  get fullName() {   
    return `${this.firstName} ${this.lastName}`;  
  }
}
set связывает свойство объекта с функцией, он будет вызываться при попытке установить это свойство
class Person {  
  set age(years) {    
    this.theAge = years;  
  }
}
Модули:
Импорт модулей
import defaultExport from "module-name";
import * as name from "module-name";
import * from 'module-name';
import { namedExport } from 'module-name';
import "module-name";
Экспорт модулей
export { name1, name2, …, nameN };
export default выражение;
export * from …;
export default function (…) { … };
Расширенные литералы объекта:
Более простой синтаксис для переменных, если они имеют одинаковые имена:
// вместо этого:
const name = "Irina";
const x = {  
  name: name,
};
// можно писать так:
const name = "Irina";
const x = {  
  name,
};
super()
const person = { name: "Irina", say: () => "Hello " };
const developer = {  
  __proto__: person,  
  say() {    
    return super.say() + this.name; 
  },
};
developer.say(); // Hello Irina
Динамические имена свойств объектов:
const myObj = {  
  ["some" + "thing"]: "123",
};
myObj.something; // 123
Новые строковые методы:
repeat()повторяет строку указанное количество раз;codePointAt()возвращает не отрицательное целое число, которое является закодированным в UTF-16 значением кодовой точки.
Новые методы объекта:
Object.is()определяет, являются ли два значения одинаковымиvar isSame = Object.is(value1, value2);Object.assign()используется для поверхностного копирования всех свойств объекта в целевой объектObject.assign(target, ...sources);- 
Object.setPrototypeOfустанавливает прототип объектаObject.setPrototypeOf(obj, prototype). 
ECMAScript2016 (ES7)
Cодержит всего две функции:
Array.prototype.includes()— проверяет, содержит ли массив элемент, возвращая в зависимости от этогоtrueилиfalse.Оператор возведения в степень
**— является эквивалентомMath.pow()
ECMAScript2017 (ES8)
String.prototype.padStart()иString.prototype.padEnd()— позволяют присоединять к строкам, в их начало или конец, некоторое количество символов для дополнения строк до заданной длины. Это полезно, если нужно выровнять текст, например, при выводе в консоль.Object.values()— возвращает массив, содержащий все значения свойств объекта, исключая любые значения в цепочке прототипов.Object.entries()— возвращает массив, содержащий все собственные свойства объекта, в виде массива пар[key, value].getOwnPropertyDescriptors()— принимает объект и возвращает все собственные дескрипторы свойств данного объекта (включая данные о геттерах и сеттерах).«Висячие» запятые в параметрах функций — позволяет ставить запятую после последнего параметра функции.
const someFunc = (var1, var2,) => {  
  //...
};
someFunc("test2", "test2",);
async/await или асинхронные функции — абстракция более высокого уровня по сравнению с промисами. Асинхронные функции позволяют избавиться от так называемого «ада коллбэков» и улучшить внешний вид и читаемость кода.
Разделяемая память (shared memory) и атомарные операции (atomics) — это функционал, который является основным улучшением движков JS.
Основная идея состоит в том, чтобы привнести в JavaScript какую-то многопоточность, для того чтоб разработчики JS могли писать высокопроизводительные параллельные программы и управлять памятью самостоятельно, а не позволять это делать движку JS.
Для этого задействуется новый тип глобального объекта SharedArrayBuffer, который хранит данные в общем пространстве памяти. Эти данные могут быть разделены между основным потоком JS и потоками web-workers.
WebWorkers предлагают протокол обмена сообщениями через события. Начиная с ES2017, мы можем создавать массив разделяемой памяти между web-workers и их создателями, используя SharedArrayBuffer.
Поскольку неизвестно, сколько времени занимает запись в разделяемую часть памяти, мы используется Atomics — способ удостоверится, что при чтении значения, любой вид операции записи завершен.
Более подробно об этом можно почитать в статье
ECMAScript2018 (ES9)
Асинхронная итерация
for-await-of— позволяет вызывать асинхронные функции, которые возвращают промис (или массив с кучей промисов) в цикле:
const promises = [  
  new Promise(resolve => resolve(1)),  
  new Promise(resolve => resolve(2)),  
  new Promise(resolve => resolve(3))];
async function testFunc() {  
  for await (const obj of promises) {    
    console.log(obj);  
  }
}
testFunc(); // 1, 2, 3
Promise.prototype.finally()— позволяет запускать код, независимо от успешного или неуспешного выполнения промиса:
fetch(myRequest)  
  .then(res => res.json())  
  .catch(error => console.error(error))  
  .finally(() => console.log("finished"));
Spread/Rest операторы для свойств объекта:
spread— позволяет создавать новый объект путем объединения свойств объекта, переданного после оператора...:
const arr = { first, second, ...others };
arr; //{ first: 1, second: 2, third: 3, fourth: 4, fifth: 5 }
rest— cинтаксис для rest оператора выглядит таким же как и для spread оператора, однако он используется для деструктуризации массивов и объектов. Фактически, rest оператор противоположен spread оператору: последний раскладывает массив на элементы, тогда как первый собирает много элементов в один.
const { first, second, ...others } = {  
  first: 1,  
  second: 2,  
  third: 3, 
  fourth: 4,  
  fifth: 5};
first; // 1
second; // 2
others; // { third: 3, fourth: 4, fifth: 5 }
Улучшения регулярных выражений:
Ретроспективные проверки (Lookbehind Assertion)
Позитивная ретроспективная проверка: (?<=Y)X, ищет совпадение с X при условии, что перед ним ЕСТЬ Y.
Негативная ретроспективная проверка: (?<!Y)X, ищет совпадение с X при условии, что перед ним НЕТ Y.
Юникодные свойства \p{…}
Несмотря на то, что это часть стандарта с 2018 года, юникодные свойства не поддерживаются в Firefox до 78 версии и в Edge до 79 версии.
Каждому символу в кодировке Юникод соответствует множество свойств, описывающих к какой «категории» относится символ и содержащих различную информацию о нём.
Например, свойство Letter у символа означает, что это буква какого-то алфавита, причём любого. А свойство Number означает, что это цифра – арабская или китайская, и т.п, на каком-то из языков.
В регулярном выражении можно искать символ с заданным свойством, указав его в \p{…}.
Например, \p{Letter} обозначает букву в любом языке. Также можно использовать запись \p{L}, так как L – это псевдоним Letter. Существуют короткие записи почти для всех свойств.
Несмотря на то, что это часть стандарта с 2018 года, юникодные свойства не поддерживаются в Firefox до 78 версии и в Edge до 79 версии.
Существует библиотека XRegExp, которая реализует «расширенные» регулярные выражения с кросс-браузерной поддержкой юникодных свойств.
В сложных регулярных выражениях запоминать группы по номерам затруднительно. Гораздо лучше — давать скобкам имена. Это делается добавлением ?<name> непосредственно после открытия скобки.
Например, поищем дату в формате «день-месяц-год»:
let dateRegexp = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/;
let str = "2021-03-30";
let groups = str.match(dateRegexp).groups;
alert(groups.year); // 2021
alert(groups.month); // 03
alert(groups.day); // 30
Флаг
s— включает режим «dotall», при котором точка.может соответствовать символу перевода строки\n
ECMAScript2019 (ES10)
Array.flat()— возвращает новый массив, в котором все элементы вложенных подмассивов были рекурсивно “подняты” на указанный уровень глубины (depth).
Вызов flat() без каких-либо аргументов сглаживает только первый уровень глубины. Можно указать необязательный аргумент глубины или вызвать функцию последовательно.
var arr1 = [1, 2, [3, 4]];
arr1.flat(); // [1, 2, 3, 4]
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat(); // [1, 2, 3, 4, [5, 6]]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2); // [1, 2, 3, 4, 5, 6]
var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Array.flatMap()— сначала применяет функцию к каждому элементу, а затем преобразует полученный результат в плоскую структуру и помещает в новый массив. Это идентичноmapфункции, с последующим применением функцииflatс параметром depth равным 1, ноflatMapчасто бывает полезным, так как работает немного более эффективно.String.trimStart()иString.trimEnd()— удаляют пробелы в начале и в конце строки соответственно.Необязательная привязка
catch— позволяет разработчикам использоватьtry/catchбез параметраerrorвнутри блокаcatch.Object.fromEntries()— создает объект или преобразует пары ключ-значение в объект. Он принимает только итерируемый объект:Object.fromEntries(iterable).Symbol.description— read-only cвойство - строка, возвращающая необязательное описание объектов Symbol
console.log(Symbol('desc').description); // expected output: "desc"
Хорошо сформированный JSON.stringify()
Исправленный вывод JSON.stringify() при обработке суррогатных кодовых точек UTF-8 (от U+D800 до U+DFFF).
Перед этим изменением вызов JSON.stringify() возвращал некорректный символ Unicode («�»).
Теперь эти суррогатные кодовые точки можно безопасно представить в виде строк, используя JSON.stringify(), и преобразовать обратно в их исходное представление, используя JSON.parse().
JSON.stringify('\uD800');
> '"�"'
JSON.stringify('\uD800');
> '"\\ud800"' 
Корректировки метода
Function.prototype.toString()
Функции всегда имели метод экземпляра toString(), который возвращает строку, содержащую код функции.
ES2019 ввел изменение в возвращаемое значение, чтобы избежать удаления комментариев и других символов, таких как пробел, точно представляющих функцию в том виде, как она была определена.
Например, для функции:
function /* a comment */ name() {}
// Поведение было таким:
name.toString();
// "function name() {}"
// Стало таким:
name.toString();
// "function /* a comment */ name () {}"
ECMAScript2020 (ES11)
String.matchAll— возвращает итератор, который в свою очередь возвращает все совпадающие группы одну за другой.
const str = "abc";
const regexp = /[a-c]/g;
const iterator = str.matchAll(regexp);
for (result of iterator) {  
  console.log(result);
}
// ["a", index: 0, input: "abc", groups: undefined]
// ["b", index: 1, input: "abc", groups: undefined]
// ["c", index: 2, input: "abc", groups: undefined]
Динамический импорт — даёт возможность динамически импортировать файлы JS в виде модулей.
let modulePath = prompt("Какой модуль загружать?");
import(modulePath)   
.then(obj => <объект модуля>)   
.catch(err => <ошибка загрузки, например если нет такого модуля>)
BigInt — это специальный числовой тип, который предоставляет возможность работать с целыми числами произвольной длины.
Т.е. это способ представлять целые числа больше pow(2, 53) - 1, максимального числа, которое JavaScript может надежно представить с Number примитивом.
Чтобы создать значение типа BigInt, необходимо добавить n в конец числового литерала или вызвать функцию BigInt, которая создаст число типа BigInt из переданного аргумента. Аргументом может быть число, строка и др.
const bigint = 1234567890123456789012345678901234567890n;  
const sameBigint = BigInt("1234567890123456789012345678901234567890");  
const bigintFromNumber = BigInt(10); // то же самое, что и 10n
Promise.allSettled— возвращает промис, который исполняется когда все полученные промисы завершены (выполнены успешно или отклонены), содержащий массив результатов исполнения полученных промисов.globalThis
В JavaScript всегда есть один большой объект контекста, который содержит всё. Традиционно в браузерах это window. Но если попытаться получить к нему доступ в Node, то будет ошибка. В Node нет глобального объекта window — вместо этого есть объект global. С другой стороны, в WebWorkers нет доступа к window, но вместо этого есть self.
globalThis всегда ссылается на глобальный объект, независимо от того, где мы выполняем свой код.
for-in mechanics — стандарт в каком порядке цикл
for (x in y)должен выполняться.Optional chaining — Оператор опциональной последовательности(
?.)
Призван сделать код короче, при работе со вложенными объектами и проверкой на undefined.
const car = {};
const color = car?.color;
const colorName = car?.color?.name;
Nullish coalescing — Оператор нулевого слияния (
??)
Возвращает значение правого операнда когда значение левого операнда равно null или undefined, в противном случае будет возвращено значение левого операнда.
const foo = null ?? 'default string';
console.log(foo);
// expected output: "default string"
const baz = 0 ?? 42;
console.log(baz);
// expected output: 0
Module namespace exports
export * as utils from "./utils.mjs";
// эквивалентно следующему:
import * as utils from "./utils.mjs";
export { utils };
ECMAScript2021 (ES12)
P.S. Данный материал был написан в начале 2021 года, для просмотра актуальной информации читайте вторую часть моей статьи :)
Ожидается, что версия ECMAScript 2021 будет выпущена в июне 2021 года. Вот некоторые из функций, которые могут оказаться в ES2021 (ES12). Список подготовлен на основе ECMAScript Proposals и новых функций, выпущенных движком Google Chrome V8.
Все функции, перечисленные ниже, на момент написания поддерживаются в сборке Google Chrome Canary (версия браузера Google Chrome, поддерживающая экспериментальные возможности).
String.prototype.replaceAll()заменяет все вхождения строки другим строковым значением.Приватные методы — могут быть доступны только внутри класса, в котором они определены. Имена приватных методов начинаются с символа #.
class Person {         
  
  #setType() {            
    console.log("I am Private");      
  }          
  
  show() {            
    this.#setType();      
  } 
}  
const personObj = new Person(); 
personObj.show(); // "I am Private"; 
personObj.setType(); // TypeError: personObj.setType is not a function
Приватные аксессоры
class Person {        
  get name() { return "Backbencher" }      
  set name(value) {}          
  
  get #age() { return 42 }       
  set #age(value) {} 
}
const obj = new Person(); 
console.log(obj.name); // "Backbencher" console.log(obj.age); // undefined
WeakRef — слабые ссылки (Weak References). В основном слабые ссылки используются для реализации кэшей или маппингов больших объектов. В таких сценариях мы не хотим удерживать большое количество памяти надолго, сохраняя редко используемый кэш или маппинг. Мы можем разрешить сборку мусора для памяти в ближайшее время, а позже, если она нам снова понадобится, мы можем создать свежий кэш.
Финализаторы (FinalizationRegistry)—это дополнительная функция WeakRef, позволяющая регистрировать коллбеки, которые будут вызываться после того, как объект был забран сборщиком мусора.
Promise.any()— успешно завершается, если успешно завершился любой из предоставленных в качестве аргументов промис.
Если ни один из промисов не завершится успешно Promise.any() сгенерирует исключение AggregateError. Нам нужно поймать это исключение и обработать.
Оператор логического присваивания (
&&=,||=,??=) — объединяет логические операции (&&,||или??) с присваиванием.
const x = 1;  
const y = 2; 
const z;
x &&= y;  // 2
x ||= y;  // 1
z ??= y;  // 2
При написании статьи использованы следующие ресурсы: