Подробный обзор новых возможностей JavaScript ES7, ES8, ES9.

JavaScript Promise ECMAScript 8
Подробный обзор новых возможностей JavaScript ES7, ES8, ES9.

Введение: Эволюция ECMAScript не остановится, но нам абсолютно нечего бояться. В дополнение к огромному количеству информации и знаний, которые приносит беспрецедентная версия ES6, версия, выпускаемая каждый год, имеет лишь небольшое количество добавочных обновлений, и требуется полчаса, чтобы понять, что обновляется за год. Быть испуганным. Эта статья займет у вас около часа, чтобы быстро ознакомиться с новыми функциями ES7, ES8 и ES9.

Если вы хотите улучшить качество чтения, пожалуйста, переместитеисходный адрес

Надпись: Эта статья предоставляет онлайн-версию PPT для вашего удобства.Подробное объяснение новых возможностей JAVASCRIPT ES7 ES8 ES9 Online PPT вер.

Большая часть этой статьи была переведена с веб-сайта автора, доктора Акселя Раушмайера.Для получения дополнительной информации об авторе посетите веб-сайтExploring JS: JavaScript books for programmers

Те вещи, которые связаны с ECMAScript

Кто разрабатывает ECMAScript?

TC39 (Технический комитет 39).

TC39 — это комитет, который продвигает разработку JavaScript. Его участниками являются компании (в основном производители браузеров). TC39 проводит регулярные заседания с участием представителей компаний-членов и приглашенных экспертов. Все протоколы собраний доступны онлайн, что дает вам четкое представление о том, как работает TC39.

Интересно, что ТК39 работает по принципу консенсуса: каждый член (представитель компании) должен одобрить резолюцию для ее принятия.

Цикл выпуска ECMAScript

ECMAScript (ES6) был выпущен в 2015 году с множеством новых дополнений, и потребовалось почти 6 лет (с 2009-11 по 2015-6), чтобы стандартизировать его после выпуска ES5. Есть две основные причины такого большого промежутка времени между релизами:

  • Функции, завершенные до новой версии, должны дождаться завершения новой версии, прежде чем их можно будет выпустить.
  • Функции, выполнение которых занимает много времени, также должны быть включены в эту версию, потому что отсрочка выпуска следующей версии означает долгое ожидание, и эта функция также задержит новую версию выпуска.

Итак, начиная с ECMAScript 2016 (ES7), релизы стали более частыми, с новым релизом каждый год, поэтому дополнений будет меньше. Новая версия будет содержать все функции, завершенные к годовому сроку.

Процесс публикации для ECMAScript

Предложения по каждой функции ECMAScript будут начинаться с этапа 0 и проходить следующие этапы зрелости. Один из них должен быть одобрен TC39 от одного этапа к другому.

  1. stage-0 - Strawman: просто идея, возможный плагин Babel. Любые обсуждения, идеи, изменения или функции, которые еще не добавлены в предложение, находятся на этом этапе. Только члены TC39 могут представить.

Текущий список этапов 0 можно посмотреть здесь -->Stage 0 Proposals

  1. stage-1 - Proposal: this is worth working on.

    **Что такое предложение? **Официальный документ с предложением новой функции. В предложениях должны быть указаны потенциальные проблемы с этим предложением, такие как связи с другими функциями, трудности реализации и т. д.

  2. stage-2 - Draft: initial spec.

    **Что такое черновик? **Черновик — первая версия спецификации. Он не будет сильно отличаться от функций, включенных в окончательный стандарт.

После черновика в принципе принимаются только добавочные изменения. На этом этапе начинаются эксперименты с реализацией, включая полифиллы, механизмы реализации (обеспечивающие встроенную поддержку чернового выполнения) или преобразования компиляции (такие как babel).

  1. stage-3 - Candidate: complete spec and initial browser implementations.

Стадия кандидата, получение конкретной реализации и отзывов пользователей. После этого он будет изменен только в том случае, если возникнут серьезные проблемы с реализацией и использованием. Реализуйте хотя бы один браузер, предоставьте плагин polyfill или babel.

  1. stage-4 - Finished: will be added to the next yearly release.

Готово, эта функция появится в следующей версии спецификации ECMAScript.

Текущий список этапов 1-3 можно посмотреть здесь -->ECMAScript proposals

Указатель функций, который был официально выпущен

Proposal Author Champion(s) TC39 meeting notes Expected Publication Year
Array.prototype.includes Domenic Denicola Domenic Denicola
Rick Waldron
November 2015 2016
Exponentiation operator Rick Waldron Rick Waldron January 2016 2016
Object.values/Object.entries Jordan Harband Jordan Harband March 2016 2017
String padding Jordan Harband Jordan Harband
Rick Waldron
May 2016 2017
Object.getOwnPropertyDescriptors Jordan Harband
Andrea Giammarchi
Jordan Harband
Andrea Giammarchi
May 2016 2017
Trailing commas in function parameter lists and calls Jeff Morrison Jeff Morrison July 2016 2017
Async functions Brian Terlson Brian Terlson July 2016 2017
Shared memory and atomics Lars T Hansen Lars T Hansen January 2017 2017
Lifting template literal restriction Tim Disney Tim Disney March 2017 2018
s (dotAll) flag for regular expressions Mathias Bynens Brian Terlson
Mathias Bynens
November 2017 2018
RegExp named capture groups Gorkem Yakin
Daniel Ehrenberg
Daniel Ehrenberg
Brian Terlson
Mathias Bynens
November 2017 2018
Rest/Spread Properties Sebastian Markbåge Sebastian Markbåge January 2018 2018
RegExp Lookbehind Assertions Gorkem Yakin
Nozomu Katō.
Daniel Ehrenberg
Daniel Ehrenberg
Mathias Bynens
January 2018 2018
RegExp Unicode Property Escapes Mathias Bynens Brian Terlson
Daniel Ehrenberg
Mathias Bynens
January 2018 2018
Promise.prototype.finally Jordan Harband Jordan Harband January 2018 2018
Asynchronous Iteration Domenic Denicola Domenic Denicola January 2018 2018
Optional catch binding Michael Ficarra Michael Ficarra May 2018 2019
JSON superset Richard Gibson Mark Miller
Mathias Bynens
May 2018 2019

Что нового в ES7 (ECMAScript 2016)

ECMAScript 2016

ES7 в основном добавляет две вещи на основе ES6:

  • Метод Array.prototype.includes()
  • оператор возведения в степень (**)

Метод Array.prototype.includes()

Метод include() используется для определения того, содержит ли массив указанное значение.В зависимости от ситуации он возвращает true, если содержит, иначе возвращает false.

var array = [1, 2, 3];

console.log(array.includes(2));
// expected output: true

var pets = ['cat', 'dog', 'bat'];

console.log(pets.includes('cat'));
// expected output: true

console.log(pets.includes('at'));
// expected output: false

Метод Array.prototype.includes() принимает два параметра:

  • значение для поиска
  • Начальный индекс поиска.

При передаче второго параметра метод начнет поиск в обратном направлении от индекса (индекс по умолчанию равен 0). Возвращает true, если искомое значение существует в массиве, иначе false. Давайте посмотрим на следующий пример:

['a', 'b', 'c', 'd'].includes('b')         // true
['a', 'b', 'c', 'd'].includes('b', 1)      // true
['a', 'b', 'c', 'd'].includes('b', 2)      // false

На первый взгляд функция include пересекается с indexOf массива, зачем добавлять такое апи? Основные отличия заключаются в следующем:

  • возвращаемое значение. Посмотрите на функцию, сначала посмотрите на ее возвращаемое значение. Возвращаемое значение indexOf является типом значения, а возвращаемое значение include является логическим типом, поэтому include намного проще при оценке условия if, а indexOf необходимо написать дополнительное условие для оценки.
var ary = [1];
if (ary.indexOf(1) !== -1) {
    console.log("数组存在1")
}
if (ary.includes(1)) {
    console.log("数组存在1")
}
  • Решение NaN. Если в массиве есть NaN, и вам просто нужно определить, есть ли NaN в массиве, то вы не можете использовать indexOf для определения, вы должны использовать метод include.
var ary1 = [NaN];
console.log(ary1.indexOf(NaN))//-1
console.log(ary1.includes(NaN))//true
  • Когда в массиве есть пустые значения, include будет рассматривать пустое значение как неопределенное, а indexOf — нет.
var ary1 = new Array(3);
console.log(ary1.indexOf(undefined));//-1
console.log(ary1.includes(undefined))//true

оператор возведения в степень (**)

Обычно мы используем его инфиксную форму для сложения/вычитания, которая интуитивно понятна и проста для понимания. В ECMAScript2016 мы можем использовать**заменить Math.pow.

4 ** 3           // 64

Эффект эквивалентен

Math.pow(4,3)

Стоит отметить, что как инфиксный оператор ** также поддерживает следующие операции:

let n = 4;
n **= 3;
// 64

Что нового в ES8 (ECMAScript 2017)

ECMAScript 2017

На конференции TC39 в январе 2017 года последняя функция ECMAScript 2017, «Общая память и атомарность», была переведена на этап 4. Это означает, что его набор функций теперь завершен.

Обзор возможностей ECMAScript 2017

Основные новые функции:

  • Асинхронные функции (Брайан Терлсон)
  • Общая память и атомарность (Ларс Т. Хансен)

Незначительные новые функции:

  • Object.values/Object.entries (Джордан Харбанд)
  • Набивка струн (Джордан Харбанд, Рик Уолдрон)
  • Object.getOwnPropertyDescriptors() (Джордан Харбанд, Андреа Джаммарки)
  • Запятые в конце в списках параметров функций и вызовах (Джефф Моррисон)

Async Functions

Асинхронные функции также известны как Async/Await, я думаю, что все знакомы с этой концепцией. Async/Await — это синтаксический сахар для обработки асинхронных операций JS, который может помочь нам избавиться от ада обратных вызовов и написать более элегантный код.

С точки зрения непрофессионала, функция ключевого слова async состоит в том, чтобы указать компилятору по-разному обрабатывать откалиброванные функции. Когда компилятор встречает ключевое слово await в откалиброванной функции, ему необходимо временно прекратить выполнение, а затем выполнить соответствующую операцию после обработки откалиброванной функции. Если функция выполнена, возвращаемое значение является значением выполнения, в противном случае — значением отклонения.

Следующее легко понять, сравнив обычный метод написания промисов:

async function asyncFunc() {
    const result = await otherAsyncFunc();
    console.log(result);
}

// Equivalent to:
function asyncFunc() {
    return otherAsyncFunc()
    .then(result => {
        console.log(result);
    });
}

Преимущество еще более заметно при последовательной обработке нескольких асинхронных функций:

async function asyncFunc() {
    const result1 = await otherAsyncFunc1();
    console.log(result1);
    const result2 = await otherAsyncFunc2();
    console.log(result2);
}

// Equivalent to:
function asyncFunc() {
    return otherAsyncFunc1()
    .then(result1 => {
        console.log(result1);
        return otherAsyncFunc2();
    })
    .then(result2 => {
        console.log(result2);
    });
}

Параллельно обрабатывать несколько асинхронных функций:

async function asyncFunc() {
    const [result1, result2] = await Promise.all([
        otherAsyncFunc1(),
        otherAsyncFunc2(),
    ]);
    console.log(result1, result2);
}

// Equivalent to:
function asyncFunc() {
    return Promise.all([
        otherAsyncFunc1(),
        otherAsyncFunc2(),
    ])
    .then([result1, result2] => {
        console.log(result1, result2);
    });
}

Обработка ошибок:

async function asyncFunc() {
    try {
        await otherAsyncFunc();
    } catch (err) {
        console.error(err);
    }
}

// Equivalent to:
function asyncFunc() {
    return otherAsyncFunc()
    .catch(err => {
        console.error(err);
    });
}

Если асинхронные функции нужно расширить, это может занять много места. Поскольку эта статья является вводной, я опять же не буду вдаваться в подробности.

SharedArrayBuffer и Atomics

Примечание, если вы ранее не знакомились со знаниями, связанными с ArrayBuffer, рекомендуется начать с комиксов из серии ускоренных курсов по управлению памятью и настоятельно рекомендуется:A crash course in memory management A cartoon intro to ArrayBuffers and SharedArrayBuffers Avoiding race conditions in SharedArrayBuffers with Atomics


ECMAScript 2017 включает SharedArrayBuffer и atomics», разработанный Ларсом Т. Хансеном. Он представляет новый конструктор SharedArrayBuffer и объект пространства имен Atomics со вспомогательными функциями.

Прежде чем мы начнем, давайте проясним два похожих, но разных термина: параллелизм и параллелизм. Для них существует множество определений, я использую следующие:

  • Параллелизм (параллельный или последовательный): выполнение нескольких задач одновременно;
  • Параллелизм (параллельный или последовательный): выполнение нескольких задач в перекрывающиеся периоды времени (а не одна за другой).

История параллелизма JS

  • JavaScript выполняется в одном потоке. Некоторые задачи могут выполняться асинхронно: браузеры обычно выполняют эти задачи в одном потоке, а затем присоединяют результаты к одному потоку с помощью обратного вызова.
  • Веб-воркеры привносят параллелизм задач в JavaScript: это относительно тяжеловесные процессы. У каждого работника есть своя глобальная среда. По умолчанию ничего не передается. Связь между воркерами (или между воркерами и основным потоком) развивается:
    • Сначала вы могли только отправлять и получать строки.
    • Затем вводятся структурированные клоны: копии данных можно отправлять и получать. Структурированное клонирование работает с большинством данных (данные JSON, TypedArray, регулярные выражения, объекты Blob, объекты ImageData и т. д.). Он даже корректно обрабатывает циклические ссылки между объектами. Однако объекты ошибок, объекты функций и узлы DOM не могут быть клонированы.
    • Переносимые данные между работниками: когда получатель получает данные, отправитель теряет доступ.
  • Используйте вычисления на графическом процессоре через WebGL (это способствует параллельной обработке данных)

Общие буферы массива

Разделяемые буферы массивов являются фундаментальными строительными блоками более высоких абстракций параллелизма. Они позволяют вам совместно использовать байты объекта SharedArrayBuffer между несколькими работниками и основным потоком (буфер является общим, чтобы получить доступ к байтам, инкапсулируйте его в TypedArray). Такое совместное использование имеет два преимущества:

Вы можете быстрее обмениваться данными между работниками. Координация между работниками становится проще и быстрее (по сравнению с postMessage() ).

// main.js
const worker = new Worker('worker.js');

// 要分享的buffer
const sharedBuffer = new SharedArrayBuffer( // (A)
    10 * Int32Array.BYTES_PER_ELEMENT); // 10 elements

// 使用Worker共用sharedBuffer
worker.postMessage({sharedBuffer}); // clone

// 仅限本地使用
const sharedArray = new Int32Array(sharedBuffer); // (B)

Создание Общего буфера массива (Shared Array Buffers) аналогично созданию обычного буфера массива (Array Buffer): вызовом конструктора и указанием размера буфера в байтах (строка A). То, чем вы делитесь с рабочими, является буфером. Для собственного локального использования вы обычно заключаете буфер общего массива в TypedArray (строка B).

Реализация воркеров указана ниже.

// worker.js
self.addEventListener('message', function (event) {
    const {sharedBuffer} = event.data;
    const sharedArray = new Int32Array(sharedBuffer); // (A)
    // ···
});

API для SharedArrayBuffer

Конструктор:

  • новый SharedArrayBuffer (длина) Создайте буфер длины байтов.

Статические свойства:

  • получить SharedArrayBuffer[Symbol.species] Это возвращается по умолчанию. Переопределите, чтобы управлять возвратом slice() .

Свойства экземпляра:

  • получить SharedArrayBuffer.prototype.byteLength() Возвращает длину буфера в байтах.

  • SharedArrayBuffer.prototype.slice(начало, конец) Создает новый экземпляр this.constructor[Symbol.species] и заполняет его байтами, начиная с (включительно) и заканчивая (исключительно).

Atomics: безопасный доступ к общим данным

Например

// main.js
sharedArray[1] = 11;
sharedArray[2] = 22;

В одном потоке вы можете переупорядочить эти записи, потому что между ними ничего не читается. С многопоточностью вы сталкиваетесь с проблемами, когда ожидаете, что запись будет выполняться в определенном порядке:

// worker.js
while (sharedArray[2] !== 22) ;
console.log(sharedArray[1]); // 0 or 11

Методы Atomics можно использовать для синхронизации с другими рабочими процессами. Например, следующие две операции позволяют читать и записывать данные без их переупорядочения компилятором:

  • Atomics.load(ta : TypedArray, index)
  • Atomics.store(ta : TypedArray, index, value : T)

Идея состоит в том, чтобы использовать обычные операции для чтения и записи большинства данных, в то время как операции Atomics (загрузка, сохранение и другие) обеспечивают безопасность чтения и записи. Как правило, вы будете использовать собственный механизм синхронизации, такой как блокировки, реализация которых основана на Atomics.

Вот очень простой пример, который всегда работает:

// main.js
console.log('notifying...');
Atomics.store(sharedArray, 0, 123);

// worker.js
while (Atomics.load(sharedArray, 0) !== 123) ;
console.log('notified');

Атомный API

Первичный операнд атомарной функции должен быть экземпляром Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array или Uint32Array. Он должен обернуть SharedArrayBuffer .

Все функции работают атомарно. Порядок операций сохранения фиксирован и не может быть изменен компилятором или процессором.

загружать и хранить

  • Atomics.load(ta: TypedArray, индекс): T Читает и возвращает элемент в ta[index], возвращая значение в указанной позиции в массиве.
  • Atomics.Store (TA: TypedArray, индекс, значение: T): T Пишет значение в Ta [Index] и возвращает значение.
  • Atomics.exchange (TA: TYPEDARRAY, INDEX, VALUE: T): T Установите для элементов TA [Index] значение Value и верните исходное значение индекса index.
  • Atomics.compareExchange(ta: TypedArray, индекс, ожидаемое значение, replaceValue): T Если текущий элемент в ta[index] — expectValue, то замените его на replaceValue. И возвращает исходное (или неизмененное) значение индекса index.

Простая модификация элементов TypeArray

Каждая из следующих функций изменяет элемент TypeArray по заданному индексу: она применяет оператор к элементу и аргументу и записывает результат обратно в элемент. Он возвращает исходное значение элемента.

  • Atomics.add(ta: TypedArray, индекс, значение): T Сделайте ta[index] += value и верните исходное значение ta[index].
  • Atomics.sub(ta: TypedArray, индекс, значение): T Сделайте ta[index] -= value и верните исходное значение ta[index].
  • Atomics.and(ta: TypedArray, индекс, значение): T Сделайте ta[index] &= value и верните исходное значение ta[index].
  • Atomics.or(ta: TypedArray, индекс, значение): T Сделайте ta[index] |= value и верните исходное значение ta[index].
  • Atomics.xor(ta: TypedArray, индекс, значение): T Сделайте ta[index] ^= value и верните исходное значение ta[index] .

подожди и проснись

  • Atomics.wait(ta: Int32Array, index, value, timeout=Number.POSITIVE_INFINITY): ('not-equal' | 'ok' | 'time-out') Возвращает «не равно», если текущее значение ta[index] не равно value . В противном случае продолжайте ждать, пока мы не проснемся через Atomics.wake() или пока не истечет время ожидания. В первом случае возвращается «ok». В последнем случае вернуть 'time-out'. тайм-аут в миллисекундах. Помните, что делает эта функция: «если ta[index] равно значению, продолжайте ждать».
  • Atomics.wake(ta: Int32Array, index, count) Просыпайтесь, подсчитывайте рабочих, ожидающих ta[index].

Object.values and Object.entries

Метод Object.values() возвращает массив всех перечисляемых значений свойств самого данного объекта в том же порядке, что и при использовании цикла for...in (отличие в том, что цикл for-in перечисляет свойства в цепочка прототипов) ).

Параметр obj — это объект, которым нужно управлять. Может быть объектом или массивом (объект с числовым индексом, [10,20,30] -> {0:10,1:20,2:30}).

const obj = { x: 'xxx', y: 1 };
Object.values(obj); // ['xxx', 1]

const obj = ['e', 's', '8']; // 相当于 { 0: 'e', 1: 's', 2: '8' };
Object.values(obj); // ['e', 's', '8']

// 当我们使用数字键值时,返回的是数字排序
// 根据键值排序
const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
Object.values(obj); // ['yyy', 'zzz', 'xxx']

Object.values('es8'); // ['e', 's', '8']

Метод Object.entries возвращает массив просматриваемых свойств [ключ, значение] самого данного объекта с тем же сопоставлением, что и Object.values. Объявление этого метода тривиально:

const obj = { x: 'xxx', y: 1 };
Object.entries(obj); // [['x', 'xxx'], ['y', 1]]

const obj = ['e', 's', '8'];
Object.entries(obj); // [['0', 'e'], ['1', 's'], ['2', '8']]

const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
Object.entries(obj); // [['1', 'yyy'], ['3', 'zzz'], ['10': 'xxx']]

Object.entries('es8'); // [['0', 'e'], ['1', 's'], ['2', '8']]

String padding

Добавлены 2 функции для объектов String: padStart и padEnd.

Как и их имена, основная цель этих функций — заполнить начало и конец строки, чтобы длина результирующей строки могла достигать заданной длины. Вы можете дополнить его определенными символами, строками или пробелами по умолчанию. Вот объявление функции:

str.padStart(targetLength [, padString])
str.padEnd(targetLength [, padString])

Первым аргументом этих функций является targetLength, длина результирующей строки. Второй параметр — необязательный padString (символ заполнения), строка, которая дополняет исходную строку. Значение по умолчанию — пробел.

'es8'.padStart(2);          // 'es8'
'es8'.padStart(5);          // '  es8'
'es8'.padStart(6, 'woof');  // 'wooes8'
'es8'.padStart(14, 'wow');  // 'wowwowwowwoes8'
'es8'.padStart(7, '0');     // '0000es8'

'es8'.padEnd(2);            // 'es8'
'es8'.padEnd(5);            // 'es8  '
'es8'.padEnd(6, 'woof');    // 'es8woo'
'es8'.padEnd(14, 'wow');    // 'es8wowwowwowwo'
'es8'.padEnd(7, '6');       // 'es86666'

Object.getOwnPropertyDescriptors

Метод getOwnPropertyDescriptors возвращает объекты описания для всех собственных свойств указанного объекта. Объекты описания свойств определяются непосредственно на объекте, а не наследуются от прототипа объекта. Основной причиной добавления этой функции в ES2017 является облегчение глубокого копирования одного объекта в другой и одновременное копирование геттера/сеттера. Заявление выглядит следующим образом:

Object.getOwnPropertyDescriptors(obj)

obj — объект, которым нужно управлять. Возвращаемые ключи объекта описания: настраиваемый, перечисляемый, доступный для записи, получение, установка и значение.

const obj = { 
  get es7() { return 777; },
  get es8() { return 888; }
};
Object.getOwnPropertyDescriptor(obj);
// {
//   es7: {
//     configurable: true,
//     enumerable: true,
//     get: function es7(){}, //the getter function
//     set: undefined
//   },
//   es8: {
//     configurable: true,
//     enumerable: true,
//     get: function es8(){}, //the getter function
//     set: undefined
//   }
// }

замыкающая запятая

Конечная запятая очень понятна в коде:

// 参数定义时
function foo(
    param1,
    param2,
) {}

// 函数调用时
foo(
    'abc',
    'def',
);

// 对象中
let obj = {
    first: 'Jane',
    last: 'Doe',
};

// 数组中
let arr = [
    'red',
    'green',
    'blue',
];

Какая польза от этого изменения?

  • Во-первых, перестановка элементов упрощается, поскольку вам не нужно добавлять и удалять запятые, если последний элемент меняет свое положение.
  • Во-вторых, это помогает системам контроля версий отслеживать изменения, которые действительно произошли. Например, из:
[
    'foo'
]

превратиться в

[
    'foo',
    'bar'
]

Заставляет строку 'foo' и строку 'bar' помечать как измененные, хотя единственное реальное изменение состоит в том, что добавляется последняя строка.

Что нового в ES9 (ECMAScript 2018)

ECMAScript 2018

Новые функции ES9 проиндексированы следующим образом:

Основные новые функции:

  • Асинхронная итерация (Доменик Деникола, Кевин Смит)
  • Rest/Spread property (Себастьян Маркбоге)

Новые возможности регулярных выражений:

  • Regexp названные группы захвата (Горьорм Якин, Даниэль Эренберг)
  • Экранирование свойств RegExp Unicode (Матиас Байненс)
  • RegExp Lookbehind Assertions (Горкем Якин, Нозому Като, Даниэль Эренберг)
  • Флаг s (dotAll) для регулярных выражений (Матиас Байненс)

Другие новые функции:

  • Promise.prototype.finally() (Джордан Харбанд)
  • Модификация строки шаблона (Тим Дисней)

Асинхронная итерация

Во-первых, давайте рассмотрим синхронные итераторы:

В ES6 появились синхронные итераторы, которые работают следующим образом:

  • Iterable: объект, по которому можно выполнить итерацию с помощью метода Symbol.iterator.
  • Итератор: объект, возвращаемый вызовом iterable[Symbol.iterator](). Он оборачивает каждый элемент итерации в объект и возвращает по одному через свой метод next().
  • IteratorResult: объект, возвращаемый функцией next(). Значение атрибута содержит итерируемый элемент, а выполненный атрибут является последним элементом после значения true.

Пример:

const iterable = ['a', 'b'];
const iterator = iterable[Symbol.iterator]();
iterator.next()
// { value: 'a', done: false }
iterator.next()
// { value: 'b', done: false }
iterator.next()
// { value: undefined, done: true }

Асинхронный ивер

Предыдущий итеративный метод синхронизирован и не применяется к асинхронным источникам данных. Например, в следующем коде readlineFromFile() не может передавать свои асинхронные данные посредством синхронной итерации:

for (const line of readLinesFromFile(fileName)) {
    console.log(line);
}

Асинхронные итераторы и обычные итераторы работают очень похоже, но асинхронные итераторы включают промисы:

async function example() {
  // 普通迭代器:
  const iterator = createNumberIterator();
  iterator.next(); // Object {value: 1, done: false}
  iterator.next(); // Object {value: 2, done: false}
  iterator.next(); // Object {value: 3, done: false}
  iterator.next(); // Object {value: undefined, done: true}

  // 异步迭代器:
  const asyncIterator = createAsyncNumberIterator();
  const p = asyncIterator.next(); // Promise
  await p;// Object {value: 1, done: false}
  await asyncIterator.next(); // Object {value: 2, done: false}
  await asyncIterator.next(); // Object {value: 3, done: false}
  await asyncIterator.next(); // Object {value: undefined, done: true}
}

Метод next() объекта асинхронного итератора возвращает обещание, а разрешенное значение аналогично обычному итератору. Применение:iterator.next().then(({ value, done })=> {//{value: ‘some val’, done: false}}

const promises = [
    new Promise(resolve => resolve(1)),
    new Promise(resolve => resolve(2)),
    new Promise(resolve => resolve(3)),
];

async function test() {
    for await (const p of promises) {
        console.log(p);
    }
}
test(); //1 ,2 3

Свойства отдыха/спреда

Это то, что мы обычно называем оставшимся параметром и оператором распространения.Эта функция была введена в ES6, но объекты роли в ES6 ограничены массивами:

restParam(1, 2, 3, 4, 5);

function restParam(p1, p2, ...p3) {
  // p1 = 1
  // p2 = 2
  // p3 = [3, 4, 5]
}

const values = [99, 100, -1, 48, 16];
console.log( Math.max(...values) ); // 100

В ES9 для объектов предоставляются массивоподобные параметры остатка и операторы распространения:

const obj = {
  a: 1,
  b: 2,
  c: 3
}
const { a, ...param } = obj;
  console.log(a)     //1
  console.log(param) //{b: 2, c: 3}

function foo({a, ...param}) {
  console.log(a);    //1
  console.log(param) //{b: 2, c: 3}
}

Именованные группы захвата регулярного выражения

пронумерованные группы захвата

//正则表达式命名捕获组
const RE_DATE = /([0-9]{4})-([0-9]{2})-([0-9]{2})/;

const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj[1]; // 1999
const month = matchObj[2]; // 12
const day = matchObj[3]; // 31

Ссылка на группы захвата по номерам имеет несколько недостатков:

  • Найти количество групп захвата непросто: необходимо использовать круглые скобки.
  • Если вы хотите понять, для чего нужны группы, вам нужно взглянуть на регулярные выражения.
  • Если вы измените порядок групп захвата, вы также должны изменить соответствующий код.

именованная группа захвата

В ES9 группы захвата можно идентифицировать по их имени:(?<year>[0-9]{4})

Здесь мы отметили название предыдущего года группы отлова. Имя должно быть допустимым идентификатором JavaScript (например, имя переменной или имя свойства). После сопоставления вы можете получить к нему доступ, обратившись к захваченной строке matchObj.groups.year.

Перепишем предыдущий код:

const RE_DATE = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/;

const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj.groups.year; // 1999
const month = matchObj.groups.month; // 12
const day = matchObj.groups.day; // 31

// 使用解构语法更为简便
const {groups: {day, year}} = RE_DATE.exec('1999-12-31');
console.log(year); // 1999
console.log(day); // 31

Можно обнаружить, что именованные группы захвата имеют следующие преимущества:

  • Легче найти «ID» группы захвата.
  • Код соответствия становится самоописываемым, поскольку идентификатор захватываемой группы описывает то, что захватывается.
  • Если вы измените порядок захвата групп, вам не нужно менять соответствующий код.
  • Имена групп захвата также облегчают повторное повторное воздействие, потому что вы можете напрямую увидеть, для чего предназначена каждая группа.

Регулярные выражения Unicode Escape

Эта функция позволяет вам использовать\p{}Чтобы сопоставлять символы, указав свойства символов Unicode внутри фигурных скобок, используйте токены в регулярных выражениях.u(Юникод) настройки.

/^\p{White_Space}+$/u.test('\t \n\r')
// true
/^\p{Script=Greek}+$/u.test('μετά')
// true

Новый метод сопоставления китайских иероглифов

Поскольку в Unicode сценарий Unicode, соответствующий китайским иероглифам,Han, поэтому мы можем использовать этот регистр для соответствия китайскому языку:

/\p{Script=Han}/u

Таким образом, мы можем избежать громоздкой и трудной памяти./[\u4e00-\u9fa5]/Кроме того, это выражение существует уже несколько лет.Честно говоря, символы с атрибутом Хан, добавленным позже, не входят в этот диапазон, поэтому этот старый регистр не обязательно прост в использовании.

Я случайно нашел в Интернете китайский символ «𬬭», добавленный Unicode8.0, и проверил совместимость двух регистров:

oldReg=/[\u4e00-\u9fa5]/
newReg=/\p{Script=Han}/u

oldReg.test('abc')
// false
newReg.test('abc')
// false

oldReg.test('地平线')
// true
newReg.test('地平线')
// true

oldReg.test('𬬭')
// false
newReg.test('𬬭')
// true

http://www.unicode.org/charts/PDF/U4E00.pdf

Вы можете обратиться к этому PDF-файлу, который представляет собой полный набор китайских иероглифов в Unicode, от 524 страниц 9FA6 до 526 страниц (последняя страница), старый метод сопоставления не может работать.

Unicode

Немного популярной науки о Unicode

  • Имя: Уникальное имя, состоящее из заглавных букв, цифр, дефисов и пробелов. Например:

    • A: Имя = ЛАТИНСКАЯ ЗАГЛАВНАЯ БУКВА A
    • 😀: Имя = УСМЕИВАЮЩЕЕСЯ ЛИЦО
  • General_Category: классифицировать персонажей. Например:

    • X: Общая_Категория = Нижняя_Буква
    • $: Общая_Категория = Символ_Валюты
  • White_Space: используется для обозначения невидимых символов пробела, таких как пробелы, табуляции и символы новой строки. Например:

    • \ T: white_space = true
    • π: White_Space = Ложь
  • Возраст: стандартная версия введенного символа Unicode. Например: символ евро € был добавлен в версии 2.1 стандарта Unicode.

    • €: Возраст = 2,1
  • Скрипт: это набор символов, используемых одной или несколькими системами письма.

    • Некоторые скрипты поддерживают несколько систем письма. Например, латиница поддерживает такие системы письма, как английский, французский, немецкий, латинский и т. д.
    • Некоторые языки могут быть написаны с использованием нескольких альтернативных систем письма, поддерживаемых несколькими сценариями. Например, в турецком языке использовалась арабская письменность до того, как в начале 20 века она была преобразована в латиницу.
    • пример:
      • альфа: сценарий = греческий
      • Д: Шрифт = Кириллица

Экранирование свойства Unicode для регулярных выражений

  • Совпадение со значением всех символов, свойства свойства которых имеют значение:

    \p{prop=value}

  • Совпадение с любым значением символа без значения реквизита свойства:

    \P{prop=value}

  • Совпадение со всеми символами, у которых бинарное свойство bin_prop равно True:

    \p{bin_prop}

  • Совпадение со всеми символами, у которых бинарное свойство bin_prop имеет значение False:

    \P{bin_prop}

  • Совпадение пробелов:

/^\p{White_Space}+$/u.test('\t \n\r')
//true

Совпадение букв:

/^\p{Letter}+$/u.test('πüé')
//true

Соедини греческие буквы:

/^\p{Script=Greek}+$/u.test('μετά')
//true

Сопоставьте латинские буквы:

/^\p{Script=Latin}+$/u.test('Grüße')
//true

Обратное утверждение регулярного выражения

Давайте сначала посмотрим, что такое утверждение с опережением в регулярном выражении:

Например, получение символа валюты

const noReLookahead = /\D(\d+)/,
      reLookahead = /\D(?=\d+)/,
      match1 = noReLookahead.exec('$123.45'),
      match2 = reLookahead.exec('$123.45');
console.log(match1[0]); // $123   
console.log(match2[0]); // $

Обратные утверждения разрешены в ES9:

const reLookahead = /(?<=\D)[\d\.]+/;
      match = reLookahead.exec('$123.45');
console.log(match[0]); // 123.45

Используйте ?

Шаблон регулярного выражения dotAll

Средняя точка регулярного выражения соответствует любому одиночному символу, кроме возврата каретки, токен s меняет это поведение, допуская появление разделителей строк, например:

/hello.world/.test('hello\nworld');  // false
/hello.world/s.test('hello\nworld'); // true

Promise.prototype.finally()

Об этом в принципе и говорить нечего, это можно понять, взглянув на название. Его использование заключается в следующем:

promise
  .then(result => {···})
  .catch(error => {···})
  .finally(() => {···});

Обратный вызов finally выполняется всегда.

Изменение строки шаблона

ES2018 снимает ограничение синтаксиса для escape-последовательностей ECMAScript в теговых строках шаблона. Раньше \u запускал escape-код в юникоде, \x запускал шестнадцатеричный escape-код, а \, за которым следовала цифра, запускал восьмеричный escape-код. Это делает невозможным создание определенных строк, таких как путь к файлу Windows C:\uuu\xxx\111.

Чтобы снять ограничение синтаксиса escape-последовательностей, используйте функцию разметки String.raw перед строкой шаблона:

`\u{54}`
// "T"
String.raw`\u{54}`
// "\u{54}"

конец

Эволюция ECMAScript не остановится, но нам совсем не нужно бояться. В дополнение к огромному количеству информации и знаний, которые приносит беспрецедентная версия ES6, версия, выпускаемая каждый год, имеет лишь небольшое количество добавочных обновлений, и требуется полчаса, чтобы понять, что обновляется за год. Быть испуганным.

Stay hungry. Stay foolish.