ECMAScript

ECMAScript (ES) — стандарт для скриптовых языков программирования, включая JavaScript, JScript и ActionScript. Наиболее известен как стандарт JavaScript, предназначенный для обеспечения взаимодействия веб-страниц между различными веб-браузерами. Стандартизируется организацией Ecma International в документе ECMA-262[13].[14]

ECMAScript обычно используется для клиентских скриптов во Всемирной паутине, а также всё чаще применяется для серверных приложений и сервисов с использованием сред выполнения, таких как Node.js[15], Deno[16] и Bun[17]. Кроме того, на его основе создаются кроссплатформенные настольные приложения с помощью фреймворков, таких как Electron (на нём построены Visual Studio Code, Slack, Discord и Microsoft Teams)[18] и мобильные приложения (например, с использованием React Native).

Что важно знать
ECMAScript
Семантика Статическая и динамическая[1]
Класс языка мультипарадигменный: объектно-ориентированное, функциональное, императивное, событийно-ориентированное[2]
Тип исполнения JIT-компиляция[3]
Появился в 1997[4]
Автор Брендан Айк[5]
Разработчик Ecma International (TC39)[5]
Расширение файлов .js, .mjs, .cjs[6]
Выпуск ECMAScript 2025[7] (25 июня 2025; 6 месяцев назад (2025-06-25)[7])
Тестовая версия ECMAScript 2026[8]
Система типов утиная
Основные реализации V8, SpiderMonkey, JavaScriptCore, ChakraCore[9]
Диалекты JavaScript, JScript, ActionScript, JScript .NET, QtScript
Испытал влияние Self[10], Си, Scheme[10], Perl[10], Python, Java[10], AWK[10]
Повлиял на Objective-J
Лицензия Разрешительная лицензия Ecma, Royalty-Free[11]
Сайт ecma-international.org/p…
Платформа кроссплатформенный[12]

ECMAScript, ECMA-262, JavaScript

ECMA-262, или ECMAScript Language Specification, определяет язык ECMAScript, или просто ECMAScript[19]. ECMA-262 определяет только синтаксис языка и семантику основной программной среды (API), такой как Array, Function, и globalThis, в то время как полноценные реализации JavaScript добавляют собственные возможности, такие как ввод-вывод и работа с файловой системой.

Файлы с исходным кодом на языке ECMAScript используют несколько расширений, выбор которых зависит от используемой модульной системы. Наиболее распространённым является расширение `.js`[20]. В современных средах, таких как Node.js, файлы с этим расширением могут интерпретироваться как модули CommonJS или как нативные модули ECMAScript (ES-модули) в зависимости от конфигурации проекта[21]. Для явного указания типа модуля были введены специальные расширения: `.mjs` используется для ES-модулей, использующих синтаксис import/export[22], а `.cjs` — для модулей CommonJS, использующих require() и module.exports[22].

История

История стандарта тесно связана с созданием языка JavaScript. В 1995 году Брендан Айк, работая в компании Netscape, разработал за 10 дней первую версию языка[23]. Изначально он назывался Mocha, затем LiveScript и, наконец, JavaScript[24]. В декабре 1995 года Sun Microsystems и Netscape анонсировали JavaScript в совместном пресс-релизе[25].

В ноябре 1996 года Netscape передала язык на стандартизацию в международную ассоциацию Ecma International[26]. Этот шаг был предпринят для обеспечения совместимости между различными браузерами и для того, чтобы предотвратить контроль над языком одной компанией[23]. В результате этой работы в июне 1997 года Генеральная ассамблея Ecma приняла первую редакцию стандарта, получившего название ECMA-262, или ECMAScript. Таким образом, Брендан Айк является автором первоначального языка, а Ecma International через свой технический комитет TC39 выступает коллективным автором и хранителем стандарта ECMAScript, который постоянно развивается[23][27].

Название «ECMAScript» стало компромиссом между организациями, участвовавшими в стандартизации языка, особенно Netscape и Microsoft, чьи споры доминировали на ранних сессиях по стандарту. Айк отмечал, что «ECMAScript всегда было нежеланным торговым названием, которое звучит как кожное заболевание»[28]. Формализация ECMAScript с помощью операционной семантики была выполнена в Стэнфордском университете и Кафедрой вычислительной техники Имперского колледжа Лондона для анализа безопасности и стандартизации[29]. «ECMA» расшифровывалось как «European Computer Manufacturers Association» до 1994 года.

Эволюция

Технический комитет 39 (TC39) организации Ecma International отвечает за развитие и поддержку стандарта ECMAScript[30]. Процесс добавления новых возможностей в язык строго регламентирован и проходит несколько стадий (от 0 до 4), отражающих степень готовности предложения. Для перехода на следующую стадию требуется консенсус внутри комитета, в который входят представители всех основных разработчиков браузеров и других заинтересованных сторон. Предложения, достигшие финальной, 4-й стадии, считаются готовыми к включению в стандарт[31].

С 2015 года комитет перешёл на ежегодный цикл выпуска новых версий. Спецификация разрабатывается в формате «живого черновика» (living draft), который постоянно обновляется и доступен публично. Ежегодно в июне из этого черновика формируется и публикуется новая официальная редакция стандарта, включающая все готовые на тот момент нововведения[31].

2016 год

В 2016 году полностью вступил в силу новый итеративный процесс разработки. В июне была опубликована седьмая редакция стандарта — ECMAScript 2016[32]. Этот выпуск был намеренно небольшим и стал первым, подготовленным в рамках ежегодного цикла. Он продемонстрировал успешность нового подхода, позволяющего быстрее внедрять готовые функции[33]. Весь процесс разработки был перенесён на GitHub, что сделало его более открытым для сообщества[34].

2018 год

В июне 2018 года был утверждён стандарт ECMAScript 2018. В течение года комитет также активно работал над будущими возможностями: на 3-ю стадию были переведены предложения, которые впоследствии вошли в ES2019, такие как Array.prototype.flat/flatMap, Object.fromEntries и необязательный параметр в блоке catch. Важные предложения, такие как BigInt и Decorators, также достигли значительного прогресса, перейдя на 3-ю и 2-ю стадии соответственно.

2021 год

22 июня 2021 года 121-я Генеральная Ассамблея Ecma International утвердила 12-е издание стандарта — ECMAScript 2021[35]. В него вошли такие нововведения, как метод String.prototype.replaceAll(), Promise.any(), логические операторы присваивания, числовые разделители, а также WeakRef и FinalizationRegistry.

2023 год

В июне 2023 года был выпущен ECMAScript 2023. Ключевыми нововведениями стали немутирующие методы для работы с массивами (toSorted(), toReversed(), toSpliced(), with()), методы поиска с конца массива (findLast(), findLastIndex()), поддержка синтаксиса «хэшбэнг» (#!) и возможность использовать символы в качестве ключей в WeakMap[36]. В этом же году долгожданное предложение по декораторам достигло 3-й стадии[37], а в процесс стандартизации была официально добавлена промежуточная стадия 2.7[38].

2025 год

25 июня 2025 года на 129-й Генеральной Ассамблее Ecma International была утверждена 16-я версия стандарта — ECMAScript 2025. В неё вошли такие возможности, как методы для работы с множествами (Set), атрибуты импорта для JSON-модулей, Promise.try(), вспомогательные методы для итераторов и улучшения для регулярных выражений[39].

ECMAScript 2015 (ES6)

ECMAScript 2015, также известный как ES6, стал одним из самых значительных обновлений стандарта языка JavaScript[40], выпущенный в июне 2015 года. Он был нацелен на решение многих распространённых проблем и упрощение написания сложного кода[41]. Эти нововведения значительно расширили возможности языка и стали основой для современной JavaScript-разработки[42].

Ключевые нововведения ECMAScript 2015 включают:

  • let и const: Были введены два новых способа объявления переменных, которые работают в блочной области видимости ({})[43]. let позволяет объявлять переменные, которые можно переопределить, в то время как const предназначен для создания констант — переменных, значение которых не может быть изменено после присваивания[40]. Это решило многие проблемы с областью видимости, которые были свойственны var[44].
  • Стрелочные функции: Появился более короткий синтаксис для написания функциональных выражений[45]. Они не только делают код более лаконичным, но и лексически привязывают значение this, что решает частые проблемы с контекстом выполнения в обратных вызовах (callbacks)[44].
  • Классы: ES6 представил синтаксический сахар для работы с прототипным наследованием в JavaScript[40]. Ключевое слово class предоставляет более простой и понятный синтаксис для создания объектов и реализации наследования, знакомый разработчикам из других языков[40].
  • Шаблонные строки: Этот функционал позволяет встраивать выражения непосредственно в строки и создавать многострочные строки[46]. Выражения вставляются с помощью конструкции ${выражение}[46].
  • Модули: Была стандартизирована модульная система с использованием ключевых слов import и export[42]. Это позволило разработчикам организовывать код в виде многократно используемых и изолированных файлов-модулей[45].
  • Параметры по умолчанию: Функции получили возможность определять значения по умолчанию для своих параметров[47].
  • Деструктуризация: Появился удобный синтаксис для извлечения значений из массивов или свойств из объектов и их присваивания переменным[48].
  • Операторы rest и spread: Оператор rest (остаточные параметры) позволяет представить неопределённое количество аргументов функции в виде массива. Оператор spread (расширение), наоборот, позволяет «распаковывать» элементы массива или свойства объекта[44].
  • Промисы: В стандарт был добавлен встроенный объект Promise для упрощения работы с асинхронными операциями. Промисы предоставляют более удобную альтернативу для работы с асинхронным кодом по сравнению с традиционными функциями обратного вызова (callbacks)[49].
  • Новые структуры данных: Были добавлены новые встроенные объекты для работы с коллекциями: Set для хранения уникальных значений и Map в качестве коллекции пар «ключ-значение»[49].
  • Цикл for...of: Новый тип цикла, который предоставляет более удобный способ итерации по перечисляемым объектам, таким как массивы, строки, Map, Set и другие[42].
  • Генераторы: Это особый тип функций, которые могут приостанавливать своё выполнение и возобновлять его позже, возвращая значение на каждом шаге[45].

ECMAScript 2016 (ES7)

ECMAScript 2016', также известный как ES7, был официально утверждён в июне 2016 года[50]. Он стал первым обновлением стандарта после крупного релиза ES2015 и намеренно включал в себя небольшое количество нововведений, чтобы продемонстрировать успешность нового ежегодного цикла выпуска версий. Основные языковые возможности, добавленные в этой версии, ограничиваются двумя пунктами[51].

  • Метод Array.prototype.includes(): Этот метод позволяет проверить, содержит ли массив определённый элемент, возвращая true или false[52]. Он представляет собой более удобную и читаемую альтернативу методу indexOf(), который для проверки наличия элемента требовал сравнения результата с -1[53]. Важным преимуществом includes() является его способность корректно обрабатывать значения NaN (Not-a-Number) в массиве, в отличие от indexOf()[52].
  • Оператор возведения в степень (**): В стандарт был добавлен инфиксный оператор ** для выполнения операции возведения в степень[52]. Он служит синтаксической заменой для Math.pow()[53]. Например, 2 ** 3 эквивалентно Math.pow(2, 3), и оба выражения вернут 8.

Эти два нововведения были единственными основными возможностями, которые достигли финальной, 4-й стадии готовности к моменту выпуска стандарта ES2016.

ECMAScript 2017 (ES8)

ECMAScript 2017', также известный как ES8, был официально утверждён в июне 2017 года[54]. Эта версия представила ряд значительных нововведений, направленных на упрощение асинхронного кода, улучшение работы с объектами и строками, а также добавление новых возможностей для низкоуровневых операций[55].

Ключевые нововведения:

  • Асинхронные функции (async/await): Самое ожидаемое нововведение, которое кардинально упростило работу с асинхронным кодом, основанным на промисах[56]. Ключевое слово async делает функцию асинхронной и гарантирует, что она вернёт промис, а await позволяет приостановить её выполнение до завершения другого промиса, что делает асинхронный код похожим на синхронный[57].
  • Новые методы для объектов: Были добавлены функции, облегчающие преобразование объектов в массивы[56].
    • Object.values(): Возвращает массив, содержащий значения всех собственных перечисляемых свойств объекта.
    • Object.entries(): Возвращает массив, который содержит массивы пар [ключ, значение] для каждого собственного перечисляемого свойства объекта[56].
    • Object.getOwnPropertyDescriptors(): Возвращает объект со всеми дескрипторами собственных свойств указанного объекта.
  • Дополнение строк (String Padding): В стандарт были добавлены два метода для работы со строками: padStart() и padEnd(). Они позволяют добавлять символы к началу или концу строки до достижения заданной длины.
  • «Висячие» запятые в списках параметров функций: Это синтаксическое улучшение позволяет ставить запятую после последнего параметра в объявлении или вызове функции. Такое изменение упрощает работу с системами контроля версий, так как добавление или удаление параметра в конце списка не приводит к изменению предыдущей строки[58].
  • Разделяемая память и Atomics: Продвинутая возможность для высокопроизводительных вычислений. SharedArrayBuffer представляет собой буфер с разделяемой памятью, доступный для нескольких потоков (например, основного потока и веб-воркеров). Глобальный объект Atomics предоставляет набор методов для выполнения атомарных операций над этим буфером, что предотвращает состояние гонки.

ECMAScript 2018 (ES9)

ECMAScript 2018', также известный как ES9', был утверждён в июне 2018 года и представил ряд важных нововведений, которые коснулись асинхронных операций, работы с объектами и регулярными выражениями[59].

Основные нововведения:

  • Асинхронная итерация (Asynchronous Iteration): Это нововведение позволяет перебирать данные, которые поступают асинхронно. Для этого был введён асинхронный итератор и цикл for await...of[60]. Теперь можно использовать ключевое слово await внутри циклов for...of, что значительно упрощает работу с асинхронными потоками данных, например, при чтении данных из файлового потока или при получении данных по сети частями[61].
  • Свойства rest/spread для объектов (Rest/Spread Properties): Функциональность операторов ... (rest и spread), ранее доступная для массивов, была расширена и на объекты[61].
    • Rest-свойства позволяют собрать оставшиеся свойства объекта в новый объект при деструктуризации[60].
    • Spread-свойства позволяют «развернуть» свойства одного объекта в другой, создавая его копию или объединяя несколько объектов[62].
  • Promise.prototype.finally(): Этот метод добавляет блок, который будет выполнен после завершения промиса — неважно, успешно (fulfilled) или с ошибкой (rejected)[62]. finally() удобен для очистки ресурсов, например, для скрытия индикатора загрузки или закрытия соединения с базой данных, так как этот код не нужно дублировать в блоках .then() и .catch()[61].
  • Улучшения в регулярных выражениях (RegExp):
    • Именованные группы захвата (Named Capture Groups): Позволяют обращаться к захваченным группам по имени, а не по индексу, что делает код более читаемым и удобным для поддержки[63].
    • Проверки назад (Lookbehind Assertions): Добавлены позитивная ({{{1}}}) и негативная (?<!...) проверки, которые позволяют сопоставить строку, которой предшествует или не предшествует определённый шаблон, не включая его в результат[63].
    • Флаг s (dotAll): С этим флагом метасимвол ., в регулярном выражении начинает соответствовать абсолютно любому символу, включая символы переноса строки, такие как \n[63].
    • Экранирование свойств Юникода (Unicode Property Escapes): Позволяет создавать регулярные выражения для поиска символов по их свойствам в Юникоде (например, {{{1}}}})[63].
  • Ослабление ограничений для шаблонных литералов: Были сняты ограничения на использование escape-последовательностей в тегированных шаблонных литералах, что исправило некоторые ошибки при работе со строками, содержащими определённые символы[63].

ECMAScript 2019 (ES10)

ECMAScript 2019', также известный как ES10', является 10-й редакцией стандарта языка JavaScript. В этой версии было представлено несколько новых возможностей и улучшений, направленных на повышение удобства и функциональности языка[64].

Основные нововведения:

  • Новые методы для массивов: flat() и flatMap()[65]. Метод Array.prototype.flat() создаёт новый массив, в котором все элементы вложенных подмассивов рекурсивно «поднимаются» на указанную глубину[65]. В свою очередь, Array.prototype.flatMap() объединяет в себе функциональность методов map() и flat() с глубиной 1[66].
  • Object.fromEntries(). Этот статический метод преобразует список пар «ключ-значение» обратно в объект[66]. Он выполняет операцию, обратную Object.entries(), и может принимать на вход любой итерируемый объект, например, массив или Map[65].
  • Новые методы для строк: trimStart() и trimEnd(). Добавлены методы, которые удаляют пробельные символы с начала и с конца строки соответственно[65]. Они являются более семантически корректными псевдонимами для уже существующих, но нестандартных trimLeft() и trimRight()[64].
  • Необязательный параметр в catch. ES2019 позволяет опускать параметр (ошибку) в блоке catch, если он не используется в коде[67]. Это делает код чище в ситуациях, когда важен сам факт перехвата исключения, а не его содержимое[68].
  • Свойство Symbol.prototype.description. Появилось свойство description, доступное только для чтения, которое возвращает строковое описание объекта Symbol[68]. Это упрощает отладку, позволяя получить доступ к описанию, с которым был создан символ[67].
  • Улучшения в JSON.stringify(). Метод был доработан для корректной обработки суррогатных пар UTF-8, предотвращая возврат некорректных символов Unicode[67].
  • Изменения в Function.prototype.toString(). Теперь метод, вызванный у функции, возвращает строку, которая в точности соответствует её исходному коду, включая комментарии и пробелы[67].
  • Стабильная сортировка Array.prototype.sort(). Спецификация теперь требует, чтобы сортировка массива была стабильной. Это означает, что элементы с одинаковым порядком сортировки сохраняют свой относительный порядок[64].

ECMAScript 2020 (ES11)

ECMAScript 2020', также известный как ES11', является одиннадцатой версией спецификации языка ECMAScript и привнёс ряд значительных нововведений, которые упрощают разработку и добавляют новые возможности в JavaScript[69].

Основные языковые возможности ECMAScript 2020:

  • BigInt: Введён новый примитивный тип данных BigInt для работы с целыми числами произвольной длины[70]. Ранее максимальное безопасное целое число в JavaScript было ограничено значением Number.MAX_SAFE_INTEGER (2⁵³ — 1)[71]. BigInt позволяет выходить за эти рамки, добавляя суффикс n к числу[71].
  • Оператор опциональной цепочки (?.): Этот синтаксис позволяет безопасно обращаться к глубоко вложенным свойствам объектов без риска возникновения ошибки, если какое-либо из промежуточных свойств равно null или undefined[71]. Если свойство не существует, выражение вернёт undefined, а не вызовет ошибку TypeError[72]. Это работает для свойств объектов, элементов массива и вызовов функций[72].
  • Оператор нулевого слияния (??): Оператор ?? является логическим оператором, который возвращает свой правый операнд, только когда левый операнд равен null или undefined[71]. В отличие от логического оператора ||, он не реагирует на другие «ложные» значения, такие как 0, "" (пустая строка) или false[71].
  • Динамический импорт import(): Эта возможность позволяет динамически (по требованию) импортировать JavaScript-модули[71]. В отличие от статического import, import() возвращает промис, что позволяет загружать модули внутри условных конструкций или асинхронных функций, реализуя, например, разделение кода (code splitting)[71].
  • Promise.allSettled(): Новый метод, который принимает массив промисов и возвращает один промис[71]. Этот промис выполняется после того, как все исходные промисы завершены (settled) — то есть либо выполнены (resolved), либо отклонены (rejected)[71]. Он возвращает массив объектов, каждый из которых отражает состояние соответствующего промиса.
  • String.prototype.matchAll(): Этот метод возвращает итератор по всем совпадениям с регулярным выражением в строке, включая захваченные группы[70]. Это более удобная альтернатива многократному вызову exec() в цикле[73].
  • globalThis: Добавлен стандартизированный способ доступа к глобальному объекту в любой среде исполнения JavaScript (в браузере это window, в Node.js — global, в веб-воркерах — self)[73]. globalThis всегда ссылается на глобальный объект, независимо от контекста.
  • Стандартизация порядка for-in: Спецификация ES2020 официально стандартизировала порядок обхода свойств в цикле for...in[71].
  • Экспорт пространства имён из модуля: Добавлен синтаксис export * as ns from 'module';, который позволяет импортировать все экспорты из одного модуля и сразу же ре-экспортировать их как единое пространство имён[73].
  • import.meta: Объект, создаваемый реализацией ECMAScript, который предоставляет метаданные о модуле, например, URL-адрес самого модуля (import.meta.url)[73].

ECMAScript 2021 (ES12)

ECMAScript 2021', также известный как ES12', является двенадцатой версией спецификации языка ECMAScript и был официально утверждён 22 июня 2021 года 121-й Генеральной Ассамблеей Ecma International. В него были добавлены несколько новых возможностей для улучшения языка JavaScript[74].

Основные нововведения:

  • Метод String.prototype.replaceAll(): Этот метод позволяет заменять все вхождения подстроки в строке, в то время как ранее доступный метод replace() заменял только первое вхождение, если не использовались регулярные выражения[75]. Теперь можно выполнить замену всех совпадений без необходимости в регулярном выражении с флагом g[75].
  • Promise.any(): Этот метод принимает массив промисов и возвращает один промис, который выполняется, как только выполняется любой из промисов в массиве[76]. Если все промисы в массиве отклоняются, Promise.any() возвращает AggregateError — новый тип ошибки, который содержит массив с причинами отклонения всех промисов[77].
  • Логические операторы присваивания: Введены три новых оператора ({{{1}}}, {{{1}}}, {{{1}}}), которые объединяют логические операции с операцией присваивания[77]. Например, {{{1}}} эквивалентно {{{1}}} (присваивание, если x — истинное значение)[74].
  • Числовые разделители: Для улучшения читаемости больших числовых литералов теперь можно использовать символ подчёркивания (_) в качестве разделителя[76]. Например, 1_000_000 будет интерпретироваться как 1000000. Это нововведение не влияет на значение числа, а служит только для визуального удобства[78].
  • WeakRef и FinalizationRegistry:
    • WeakRef (слабые ссылки) позволяет создавать слабые ссылки на объекты. Слабая ссылка не мешает сборщику мусора удалить объект, если на него не осталось сильных ссылок[76]. Это может быть полезно для реализации кэшей или сопоставлений с большими объектами.
    • FinalizationRegistry позволяет регистрировать колбэк-функции, которые будут вызваны после того, как объект был удалён сборщиком мусора[77].

ECMAScript 2022 (ES13)

Спецификация ECMAScript 2022', также известная как ES13', была официально утверждена Ecma International в июне 2022 года и привнесла ряд новых возможностей в язык JavaScript[79]. Эти нововведения направлены на улучшение синтаксиса, повышение удобства и расширение функциональности языка.

Ключевые нововведения ECMAScript 2022:

  • Верхнеуровневый await в модулях (Top-level await): Это нововведение позволяет использовать оператор await на верхнем уровне ES-модулей без необходимости оборачивать его в асинхронную функцию async[80]. Это упрощает динамическую загрузку модулей, инициализацию ресурсов и другие асинхронные операции на старте приложения[79].
  • Метод .at() для индексируемых типов данных: Для массивов, строк и типизированных массивов (TypedArray) был добавлен метод .at()[81]. Он предоставляет более удобный способ доступа к элементам, особенно при работе с конца. В отличие от скобочной нотации, .at() принимает отрицательные индексы, где -1 ссылается на последний элемент, -2 — на предпоследний и так далее[79].
  • Свойство .cause у объектов ошибок (Error Cause): Объекты Error теперь поддерживают свойство cause, которое позволяет указать исходную ошибку, приведшую к возникновению текущей[80]. Это помогает создавать цепочки ошибок, что значительно упрощает отладку и логирование, так как можно отследить всю последовательность сбоев[79].
  • Новые возможности классов: ES2022 значительно расширил функциональность классов, добавив элементы, которые ранее были доступны только при использовании TypeScript или транспайлеров[80]:
    • Приватные поля и методы экземпляра: Поля и методы, названия которых начинаются с символа #, теперь являются приватными и доступны только внутри класса[80].
    • Публичные и приватные статические поля и методы: Классы теперь могут иметь статические поля и методы (как публичные, так и приватные), которые принадлежат самому классу, а не его экземплярам.
    • Статические блоки инициализации: static { ... } — специальный блок внутри класса, который выполняется один раз при его инициализации. Это удобно для сложной логики настройки статических свойств.
    • Эргономичная проверка на наличие приватных полей: Оператор in теперь можно использовать для проверки, есть ли у объекта приватное поле, не вызывая при этом ошибки[82].
  • Индексы совпадений в регулярных выражениях (RegExp Match Indices): При использовании регулярных выражений с новым флагом /d, результат совпадения теперь включает свойство indices. Этот массив содержит начальный и конечный индексы для каждого захваченного подстрочного совпадения, что полезно для задач, где требуется знать точное положение совпадений в исходной строке.
  • Метод Object.hasOwn(): Этот статический метод является более надёжной альтернативой Object.prototype.hasOwnProperty(). Object.hasOwn(obj, prop) проверяет, является ли prop собственным (не унаследованным) свойством объекта obj, избегая потенциальных конфликтов и ошибок, которые могли возникнуть при использовании hasOwnProperty[83].

ECMAScript 2023 (ES14)

ECMAScript 2023', также известный как ES14', является 14-й редакцией стандарта, официально утверждённой в июне 2023 года[84]. Эта версия привнесла в язык ряд нововведений, направленных на улучшение работы с массивами и повышение удобства для разработчиков[85].

Ключевые нововведения:

  • Немутирующие методы для работы с массивами. В отличие от своих аналогов (sort(), reverse(), splice()), эти новые методы возвращают новую копию массива с изменениями, оставляя исходный массив нетронутым, что упрощает работу с неизменяемыми данными[85]. К ним относятся:
    • toSorted() — возвращает новый отсортированный массив.
    • toReversed() — возвращает новый массив с элементами в обратном порядке.
    • toSpliced() — возвращает новый массив с удалёнными и/или добавленными элементами.
    • with() — возвращает новую копию массива, в которой элемент по указанному индексу заменён новым значением[86].
  • Поиск с конца массива. Были добавлены методы findLast() и findLastIndex(), которые осуществляют поиск элементов с конца массива к началу, что является зеркальным поведением по отношению к find() и findIndex()[87].
  • Поддержка символов в качестве ключей в WeakMap. Ранее WeakMap позволял использовать в качестве ключей только объекты. Теперь в качестве ключей можно использовать и уникальные (незарегистрированные) символы[88].
  • Грамматика «хэшбэнг» (Hashbang Grammar). Добавлена поддержка синтаксиса «хэшбэнг» (#!) в начале файлов скриптов. Эта конструкция позволяет указать, какой интерпретатор должен использоваться для выполнения файла, что делает создание исполняемых JavaScript-файлов (например, для Node.js) более стандартизированным[89].

ECMAScript 2024 (ES15)

ECMAScript 2024', также известный как ES15', является 15-й редакцией спецификации языка, официально утверждённой в июне 2024 года[90]. Он добавляет в JavaScript ряд новых возможностей, направленных на упрощение работы с данными, асинхронными операциями и строками[90].

Ниже перечислены основные нововведения, вошедшие в финальную версию стандарта[90].

  • Object.groupBy() и Map.groupBy()
    Эти статические методы предоставляют удобный способ группировки элементов итерируемого объекта по заданному критерию[91]. Ранее для выполнения подобной операции требовалось вручную перебирать массив и использовать такие методы, как reduce()[92].
    • Object.groupBy() возвращает обычный объект, где ключами являются строки, полученные от группирующей функции[92].
    • Map.groupBy() возвращает Map, что позволяет использовать в качестве ключей значения любых типов и сохранять порядок вставки[92].
  • Promise.withResolvers()
    Этот статический метод упрощает создание и управление промисами, состояние которых нужно контролировать извне[92]. Он возвращает объект, содержащий сам промис (promise), а также функции для его успешного выполнения (resolve) и отклонения (reject)[93]. Это избавляет от необходимости создавать замыкания для доступа к функциям resolve и reject вне конструктора промиса[92].
  • Новые возможности для работы со строками Unicode
    Были добавлены два метода для проверки и исправления строк, содержащих некорректно сформированные суррогатные пары UTF-16[90].
    • String.prototype.isWellFormed(): проверяет строку и возвращает true, если она корректно сформирована, и false в противном случае.
    • String.prototype.toWellFormed(): возвращает новую строку, в которой все некорректные суррогатные пары заменены на символ-заменитель Юникода (U+FFFD)[94].
  • Флаг /v для регулярных выражений
    Новый флаг /v расширяет возможности флага /u (unicode) и добавляет поддержку операций над множествами символов, таких как объединение, пересечение и вычитание, прямо в регулярных выражениях[95]. Это позволяет создавать более сложные и точные шаблоны для работы со строками, включающими символы Unicode.
  • Atomics.waitAsync()
    Этот метод позволяет асинхронно ожидать изменения значения в SharedArrayBuffer без блокировки основного потока[95]. В отличие от синхронного Atomics.wait(), waitAsync возвращает промис, который будет выполнен, когда воркер уведомит об изменении значения. Это делает его идеальным для использования в основном потоке браузера.
  • Изменяемые и передаваемые ArrayBuffer
    Это нововведение включает в себя две ключевые возможности для работы с бинарными данными:
    • Изменяемые буферы: ArrayBuffer и SharedArrayBuffer теперь можно создавать с опциональным параметром maxByteLength, что позволяет изменять их размер в пределах этого лимита с помощью метода resize()[95].
    • Передача буферов: Метод ArrayBuffer.prototype.transfer() позволяет передавать владение ArrayBuffer другому объекту, что делает исходный буфер непригодным для использования. Это полезно для оптимизации производительности, так как предотвращает копирование данных[90].

ECMAScript 2025 (ES16)

ECMAScript 2025', также известный как ES16', является 16-й версией стандарта, официально утверждённой 25 июня 2025 года на 129-й Генеральной Ассамблее Ecma International. Новая версия привнесла ряд значимых улучшений, направленных на повышение выразительности и удобства написания кода[96].

Ключевые нововведения:

  • Новые методы для множеств (Set): В стандарт были добавлены методы для выполнения операций из теории множеств, такие как intersection (пересечение), union (объединение), difference (разность) и другие. Это позволяет более декларативно и читаемо работать с наборами данных[96].
  • Атрибуты импорта: Стандартизирована возможность импортировать JSON-файлы как модули с помощью синтаксиса with { type: 'json' }[96].
  • Promise.try(): Новый статический метод, который упрощает обработку ошибок в цепочках промисов, предоставляя более прямой способ их запуска и обработки как синхронных, так и асинхронных исключений.
  • Вспомогательные методы для итераторов: Итераторы получили набор вспомогательных методов (.map(), .filter(), .take(), .drop() и др.), которые позволяют обрабатывать данные «на лету» без необходимости предварительно преобразовывать итератор в массив[96].
  • Улучшения регулярных выражений: Введены несколько улучшений, включая статический метод RegExp.escape() для экранирования символов, возможность использовать дублирующиеся имена для именованных групп захвата и модификаторы шаблонов, позволяющие применять флаги (например, для игнорирования регистра) к части выражения[96].
  • Float16Array: Добавлен новый типизированный массив для работы с 16-битными числами с плавающей запятой, что важно для взаимодействия с системами, использующими этот формат данных, например, в WebGPU или задачах искусственного интеллекта[96].

ECMAScript 2026 и будущие версии (ES.Next)

ECMAScript 2026', следующая версия стандарта языка JavaScript, находится в стадии активной разработки. Окончательный список новых возможностей будет утверждён комитетом TC39 ближе к дате выпуска, однако на данный момент несколько ключевых предложений достигли высокой степени готовности и с большой вероятностью войдут в новую спецификацию.

Предложения для включения в стандарт проходят несколько стадий (от 0 до 4). Достижение стадии 3 («Кандидат») означает, что предложение полностью спроектировано и ожидается его включение в стандарт. Дальнейшие изменения вносятся только для исправления критических проблем, выявленных в ходе реализации и тестирования[97].

Ключевые предложения-кандидаты, которые могут войти в ECMAScript 2026:

API Temporal (стадия 3)
Это одно из самых ожидаемых нововведений, представляющее собой современный и всеобъемлющий API для работы с датами и временем[98]. Temporal призван полностью заменить существующий объект Date, который давно критикуется за многочисленные проблемы, такие как изменяемость объектов, сложность работы с часовыми поясами и запутанный API[98]. Ключевые преимущества Temporal:

  • Неизменяемые (иммутабельные) объекты: Все объекты Temporal являются неизменяемыми, что предотвращает случайные ошибки и побочные эффекты[98].
  • Простой и понятный API: Temporal предоставляет отдельные классы для разных задач, например, Temporal.PlainDate (дата без времени), Temporal.PlainTime (время без даты) и Temporal.ZonedDateTime (дата и время с учётом часового пояса)[99].
  • Надёжная работа с часовыми поясами: Встроенная и предсказуемая поддержка часовых поясов, включая переходы на летнее время[99].
  • Высокая точность: Поддержка наносекундной точности[98].

Декораторы (стадия 3)
Декораторы предлагают новый синтаксис для расширения и модификации классов и их членов (методов, полей, геттеров и сеттеров)[100]. Эта функциональность уже давно популярна в экосистеме JavaScript благодаря таким инструментам, как TypeScript, и теперь стандартизируется для нативного использования[101]. Декораторы представляют собой функции, которые применяются к классам или их элементам с помощью символа @ и позволяют добавлять новое поведение, не изменяя исходный код самого класса[100].

<code class="lang-js">
@defineElement("my-class")
class C extends HTMLElement {
  @reactive accessor clicked = false;
}
</code>

Другие возможные нововведения (стадия 3):

  • Array.fromAsync: Создаёт массив из асинхронных итерируемых объектов.
  • JSON.parse source text access: Предоставляет доступ к исходному тексту (строке) при разборе JSON, что позволяет избежать повторного синтаксического анализа для больших чисел или других специфичных данных.
  • Явное управление ресурсами (Explicit Resource Management): Аналог using из C#, который позволяет надёжно управлять жизненным циклом ресурсов, таких как файловые дескрипторы или сетевые соединения.
  • Метаданные декораторов (Decorator Metadata): Дополнение к предложению о декораторах, позволяющее прикреплять к ним метаданные.

Официальный состав ECMAScript 2026 будет окончательно утверждён после того, как эти и другие предложения достигнут стадии 4 («Готово»).

Особенности

ECMAScript является мультипарадигменным языком, что позволяет разработчикам использовать и комбинировать различные стили программирования для решения задач[102]. Основные поддерживаемые парадигмы:

Императивность и структурность

ECMAScript (JavaScript) поддерживает структурное программирование в стиле C. Ранее JavaScript поддерживал только функциональную область видимости с помощью ключевого слова var, но ECMAScript 2015 добавил ключевые слова let и const, что позволило JavaScript поддерживать как блочную, так и функциональную область видимости. JavaScript поддерживает автоматическую вставку точек с запятой, что позволяет опускать точки с запятой, которые обычно завершают оператор в C[107].

Как и в языках семейства C, управление потоком осуществляется с помощью операторов while, for, do / while, if / else, и switch. Функции слабо типизированы и могут принимать и возвращать значения любого типа. Аргументы, не переданные функции, по умолчанию равны undefined.

Слабая типизация

ECMAScript — слабо типизированный язык. Это означает, что определённые типы присваиваются неявно в зависимости от выполняемой операции. Однако в реализации JavaScript существуют особенности преобразования переменных из одного типа в другой, которые стали предметом обсуждения в юмористическом докладе «Wat»[108].[109]

Динамичность

ECMAScript — динамически типизированный язык. Тип связывается со значением, а не с выражением. ECMAScript поддерживает различные способы проверки типа объектов, включая утиную типизацию[110].

Семантика языка

Семантика языка ECMAScript, формально описанная в стандарте ECMA-262, представляет собой набор правил, которые определяют значение и поведение конструкций языка. В отличие от синтаксиса, который диктует, как правильно писать код, семантика определяет, что этот код будет делать при его выполнении. Стандарт использует формальный подход для описания семантики, чтобы обеспечить единообразную реализацию языка в различных средах[111].

Ключевые аспекты семантики ECMAScript делятся на две основные категории: статическую и динамическую (времени выполнения).

Статическая семантика

Статическая семантика (англ. Static Semantics) включает в себя правила, которые можно проверить до начала выполнения кода[111], на этапе его парсинга. Эти правила обычно связаны с синтаксическими конструкциями и выявляют ошибки на ранней стадии. Нарушения этих правил классифицируются в спецификации как «ранние ошибки» (англ. Early Errors) и не позволяют коду выполниться[111]. Примерами таких правил являются:

  • Запрет на использование ключевого слова await в качестве идентификатора внутри асинхронных функций[112].
  • Невозможность повторного объявления переменной с помощью let или const в одной и той же области видимости.

Динамическая семантика

Динамическая семантика (англ. Runtime Semantics), или семантика времени выполнения, описывает поведение кода в процессе его исполнения[111]. Центральным понятием здесь является контекст выполнения (англ. Execution Context).

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

  • Глобальный контекст выполнения (англ. Global Execution Context): базовый контекст, создаваемый при запуске скрипта. Он представляет собой глобальную область видимости.
  • Контекст выполнения функции (англ. Function Execution Context): новый контекст создаётся каждый раз при вызове функции. Когда функция завершает свою работу, её контекст уничтожается[114].

Каждый контекст выполнения включает в себя несколько компонентов, ключевыми из которых являются:

  • LexicalEnvironment (Лексическое окружение): используется для сопоставления идентификаторов (имён переменных и функций), которые появляются в коде, с их значениями. Этот компонент определяет область видимости[114].
  • VariableEnvironment (Окружение переменных): также связан с переменными, но имеет отличия в поведении, например, при обработке объявлений var.
  • ThisBinding: определяет значение ключевого слова this внутри контекста[114].

Процесс выполнения кода в ECMAScript описывается через абстрактные и синтаксически-ориентированные операции. Это внутренние функции спецификации, которые пошагово определяют, что должно произойти при выполнении той или иной конструкции. Например, для оператора сложения + определены чёткие шаги, включающие приведение операндов к примитивным значениям и последующее выполнение либо сложения чисел, либо конкатенации строк.

Ещё одним важным элементом семантики является спецификационный тип Completion Record. Он используется для представления результата выполнения любой операции[115]. Этот результат может быть либо нормальным завершением (например, возврат значения), либо «резким» завершением (англ. abrupt completion), таким как return, break, continue или throw[111]. Это позволяет точно и последовательно описывать передачу управления в программе.

Тип исполнения (JIT-компиляция)

ECMAScript, стандарт, на котором основан язык JavaScript, не является в чистом виде ни интерпретируемым, ни компилируемым языком. Современные движки JavaScript используют гибридный подход, известный как JIT-компиляция (англ. Just-in-Time, «компиляция на лету»).

Исторически первые движки JavaScript были интерпретаторами, что обеспечивало быстрый запуск, но невысокую производительность[116]. С развитием языка и усложнением веб-приложений этого стало недостаточно. Современный процесс исполнения кода в движках, таких как V8 (используется в Chrome и Node.js) или SpiderMonkey (Firefox), выглядит следующим образом[117]:

  1. Парсинг: Исходный код считывается и преобразуется в абстрактное синтаксическое дерево (англ. Abstract Syntax Tree, AST) — древовидную структуру, представляющую код[116].
  2. Интерпретация: Интерпретатор проходит по AST и генерирует промежуточный код, называемый байт-кодом. Этот этап позволяет начать выполнение кода практически сразу, без задержки на полную компиляцию[116].
  3. Профилирование: Во время выполнения специальный модуль (профилировщик) отслеживает, какие части кода (функции) выполняются особенно часто. Такие участки называют «горячими» (англ. hot spots)[118].
  4. JIT-компиляция: «Горячие» участки кода передаются оптимизирующему JIT-компилятору. Он преобразует байт-код этих участков в высокооптимизированный машинный код, который выполняется процессором напрямую[119]. Это значительно ускоряет повторное выполнение данных функций.

Таким образом, реализация ECMAScript сочетает в себе преимущества обоих подходов:

  • от интерпретации — быстрый старт выполнения программы;
  • от компиляции — высокая скорость выполнения для часто используемого кода, сопоставимая со статически компилируемыми языками.

Поэтому корректно называть JavaScript (и, соответственно, реализацию ECMAScript) языком с динамической JIT-компиляцией.

Транспиляция

Транспиляция (англ. transpilation) — это процесс компиляции исходного кода на одной версии языка в эквивалентный код на другой, как правило, более старой версии. В экосистеме JavaScript транспиляция стала стандартной практикой после выхода стандарта ES2015 (ES6)[120]. Она позволяет разработчикам использовать новейшие возможности языка, обеспечивая при этом обратную совместимость со старыми браузерами, которые их не поддерживают. Эволюция инструментов транспиляции отражает ключевые тенденции в развитии JavaScript: от стремления к новому синтаксису до гонки за производительность сборки.

2015—2019: Эпоха Babel и TypeScript

С выходом ES2015, который привнёс в язык множество нововведений, Babel быстро стал стандартом де-факто для транспиляции[121]. Он преобразовывал код, написанный на ES2015+ и JSX, в обратно совместимый код на стандарте ES5. Параллельно набирал популярность TypeScript — надмножество JavaScript, добавляющее статическую типизацию. Его компилятор (tsc) также выполнял функцию транспиляции[121].

Ключевым событием стал выпуск Babel 7 в 2018 году, который представил пресет @babel/preset-typescript[122]. Это позволило Babel «понимать» и удалять синтаксис TypeScript, оставляя проверку типов самому компилятору tsc. Такой гибридный подход стал отраслевым стандартом: Babel отвечал за транспиляцию и совместимость, а TypeScript — за надёжность и качество кода[123].

2020—2025: Гонка за производительность

К 2020 году размеры проектов значительно выросли, и производительность инструментов сборки стала критически важной. Это привело к появлению нового поколения транспиляторов, написанных на компилируемых языках с фокусом на скорость.

  • esbuild — написанный на Go и выпущенный в 2020 году, продемонстрировал 10-100-кратное превосходство в скорости над существующими инструментами на JavaScript[124].
  • SWC (англ. Speedy Web Compiler) — написанный на Rust, показал себя как сверхбыстрая замена Babel, опережая его по скорости до 20 раз на одном ядре процессора[125].

Начиная с 2021—2022 годов, ведущие фреймворки и инструменты начали активно внедрять новые транспиляторы: Next.js перешёл на SWC[126], а Vite стал использовать esbuild для ускорения сервера разработки[127].

К 2025 году ландшафт транспиляции окончательно сместился в сторону производительности. Роль Babel изменилась: он по-прежнему ценен за свою обширную экосистему плагинов и поддержку экспериментальных функций, но для стандартных задач транспиляции всё чаще используются SWC и esbuild[128]. Кроме того, появились комплексные среды выполнения, такие как Bun, которые включают в себя встроенный высокопроизводительный транспилятор, нативно поддерживающий JavaScript, TypeScript и JSX[129].

Реализации (движки)

ECMAScript, стандарт, лежащий в основе языка JavaScript, имеет несколько ключевых реализаций, известных как «движки JavaScript»[130]. Эти движки представляют собой программы или интерпретаторы, которые выполняют код, написанный на JavaScript[130]. Разрабатываемые в основном производителями веб-браузеров, каждый крупный браузер имеет свой собственный движок.

Основные реализации стандарта ECMAScript:

  • V8 — это высокопроизводительный движок JavaScript и WebAssembly с открытым исходным кодом, разработанный Google и написанный на C++. Он используется в браузере Chrome, а также является ключевым компонентом серверной платформы Node.js. V8 может работать как автономно, так и встраиваться в любое приложение на C++.
  • SpiderMonkey — это движок JavaScript и WebAssembly от Mozilla, используемый в браузере Firefox. Он написан на C++, Rust и JavaScript. Первый в истории движок JavaScript, созданный Бренданом Айком в 1995 году для браузера Netscape Navigator, со временем эволюционировал в SpiderMonkey. Его можно встраивать в проекты на C++ и Rust, а также запускать как отдельную оболочку.
  • JavaScriptCore — это фреймворк от Apple, который обеспечивает возможность выполнения программ на JavaScript. Он используется в браузере Safari и других продуктах Apple[131]. JavaScriptCore позволяет разработчикам встраивать пользовательские объекты в среду JavaScript из приложений, написанных на Swift, Objective-C и C.
  • ChakraCore — это движок JavaScript с C API, который позволяет добавлять поддержку JavaScript в проекты на C или совместимых с ним языках. Изначально он использовался в браузере Microsoft Edge, но позже Edge перешёл на использование движка V8[130].

Помимо этих основных движков, существует и множество других, часто предназначенных для более специфических задач:

  • QuickJS — небольшой и встраиваемый движок JavaScript, поддерживающий спецификацию ES2020. Он отличается малым размером, быстрым временем запуска и почти полной поддержкой стандарта.
  • Движки для микроконтроллеров — существуют реализации, разработанные специально для устройств с ограниченными ресурсами, такие как mJS и XS. Эти движки обычно поддерживают ограниченное подмножество стандарта ECMAScript.

Изначально первые движки JavaScript были простыми интерпретаторами, но все современные основные реализации используют JIT-компиляцию (just-in-time compilation) для значительного повышения производительности.

Соответствие стандарту

Test262 — это официальный набор тестов для проверки соответствия реализаций JavaScript спецификации ECMAScript[132]. Он позволяет проверить, насколько реализация JavaScript соответствует стандарту. Набор тестов содержит тысячи отдельных тестов, каждый из которых проверяет определённые требования спецификации. Разработка Test262 — проект технического комитета 39 (TC39) Ecma, и предоставление тестов является обязательным условием для продвижения новых языковых возможностей на финальную, 4-ю стадию[132].

Важный вклад в разное время внесли Google (набор тестов Sputnik) и Microsoft, которые предоставили тысячи тестов. По состоянию на май 2025 года, Test262 состоит из более чем 50 000 отдельных тестовых файлов[132].

Современные реализации JavaScript в основных веб-браузерах обеспечивают практически полную поддержку стандартов вплоть до ES2022. Стандарт ES5 поддерживается на 100 %[133], а ES2015 (ES6) — почти полностью, за исключением оптимизации хвостовых вызовов в некоторых движках[134]. Новые возможности, представленные в ежегодных релизах с 2016 года, как правило, оперативно внедряются разработчиками браузеров. В таблице ниже показан уровень соответствия для актуальных версий программного обеспечения по отношению к последним редакциям ECMAScript.

Соответствие скриптовых движков
Скриптовый движок Пример приложения[135] Соответствие[136]
ES5[133] ES6 (2015)[134] ES2016+[137] Next[138][139]
SpiderMonkey Firefox 142 100 % 98 % 100 % 85 %
V8 Google Chrome 140, Microsoft Edge 138 100 % 98 % 100 % 85 %
JavaScriptCore Safari 18.6 100 % 100 % 100 % 43 %

Поддержка стандарта ECMAScript 2025, утверждённого в июне 2025 года, активно внедряется в браузеры. Ряд ключевых нововведений уже получил статус «Baseline», что означает их поддержку во всех основных браузерных движках. К таким возможностям относятся, например, Promise.try()[140], новые методы для работы с множествами (Set)[141] и вспомогательные методы для итераторов[142].

Лицензирование

Стандарт ECMAScript, официально известный как ECMA-262, регулируется политиками интеллектуальной собственности (IPR) организации Ecma International. С июня 2022 года, по инициативе Mozilla и других членов технического комитета TC39, для спецификаций ECMAScript (ECMA-262) и API интернационализации (ECMA-402) была принята новая, более гибкая лицензионная политика[143]. Этот шаг был предпринят для лучшей совместимости с другими веб-стандартами, разрабатываемыми консорциумом W3C, такими как HTML и CSS[143].

В настоящее время для стандартов Ecma существуют две опции лицензирования:

  • Стандартная лицензия Ecma International — более строгая лицензия, направленная на предотвращение разделения стандарта, но разрешающая его воспроизведение и встраивание.
  • Альтернативная разрешительная лицензия — именно эта лицензия была принята для стандарта ECMAScript. Она основана на лицензии W3C «Document and Software License» и является более свободной в отношении создания производных работ.

Помимо лицензии на сам текст документа, стандарт ECMAScript подпадает под действие бесплатной патентной политики (англ. Royalty-Free Patent Policy) Ecma International[144]. Это означает, что патенты, необходимые для реализации стандарта, должны предоставляться на безвозмездной основе[144]. Все свежие редакции стандарта, включая ECMAScript® 2025, подготовлены в соответствии с этой патентной политикой. Публикации Ecma International, включая стандарты, могут свободно копироваться всеми заинтересованными сторонами без ограничений по авторскому праву[144].

Логотип

У стандарта ECMAScript нет собственного официального логотипа. Вместо этого с ним ассоциируются несколько эмблем: неофициальный, но общепринятый логотип JavaScript, логотип стандартизирующей организации Ecma International и неофициальные логотипы для отдельных версий стандарта, созданные сообществом[145].

Чаще всего для обозначения ECMAScript используется эмблема JavaScript, которая также не является официальной, поскольку нет единой организации, управляющей брендом JavaScript[146]. Наиболее узнаваемый вариант представляет собой жёлтый щит с чёрными буквами «JS»[146], который приобрёл свой нынешний вид в 2011 году[147]. Он был создан в едином стиле с логотипами HTML и CSS[148]. Несмотря на неофициальный статус, этот логотип повсеместно используется для обозначения языка[146].

Официальные документы и спецификации стандарта публикуются под логотипом организации Ecma International, который представляет собой её стилизованное название[149].

Примечания

Ссылки