EcmaScript 10 — JavaScript в этом году

    Стандартизация JS перешла на годичный цикл обновлений, а начало года — отличное время для того чтобы узнать, что нас ждёт в юбилейной — уже десятой редакции EcmaScript!


    ES9 — актуальная версия спецификации.


    ES10 — всё ещё черновик.


    На сегодняшний день в Stage 4 # — всего несколько предложений.


    А в Stage 3 # — целая дюжина!


    Из них, на мой взгляд, самые интересные — приватные поля классов #, шебанг грамматика для скриптов #, числа произвольной точности #, доступ к глобальному контексту # и динамические импорты #.


     
    КДПВ: Жёлтый магнит с надписью «JS ES10» на экране монитора —  от kasper.green & elfafeya.art
            Автор фото: kasper.green; Жёлтый магнит: elfafeya.art & kasper.green


    Содержание


    Пять стадий #


    Stage 4 — Final #


    •      catch — аргумент стал необязательным #;


    •      Symbol().description — акцессор к описанию символа #;


    •      'строки EcmaScript' — улучшенная совместимость с JSON форматом #;


    •      .toString() — прототипный метод обновлён #.




    Stage 3 — Pre-release #


    •      # — приватное всё у классов, через октоторп #;


    •      #!/usr/bin/env node — шебанг грамматика для скриптов #;


    •      BigInt() — новый примитив, для чисел произвольной точности #;


    •      globalThis — новый способ доступа к глобальному контексту #;


    •      import(dynamic) — динамический импорт #;


    •      import.meta — мета-информация о загружаемом модуле #;


    •      Object.fromEntries() — создание объекта из массива пар — ключ\значение #;


    •      JSON.stringify() — фикс метода #;


    •      RegExp — устаревшие возможности #;


    •      .trimStart() и .trimEnd() — прототипные методы строк #;


    •      .matchAll().match() с глобальным флагом #;


    •      .flat() и .flatMap() — прототипные методы массивов #.


    Итоги #




    Пять стадий


       Stage 0   ↓   Strawman  Наметка           Идея, которую можно реализовать через Babel-плагин.;


       Stage 1   ↓   Proposal  Предложение     Проверка жизнеспособности идеи.;


       Stage 2   ↓   Draft  Черновик                  Начало разработки спецификации.;


       Stage 3   ↓   Candidate  Кандидат         Предварительная версия спецификации.;


       Stage 4  ֍  Finished  Завершён           Финальная версия спецификации на этот год.




    Мы рассмотрим только Stage 4 — де-факто, вошедший в стандарт.


    И Stage 3 — который вот-вот станет его частью.




     


    ֍ Stage 4


    Эти изменения уже вошли в стандарт.


    Необязательный аргумент у catch


    https://github.com/tc39/proposal-optional-catch-binding


    До ES10 блок catch требовал обязательного аргумента для сбора информации об ошибке, даже если она не используется:


    function isValidJSON(text) {
      try {
        JSON.parse(text);
        return true;
      } catch(unusedVariable) { // переменная не используется
        return false;
      }
    }


    Edge пока не обновлён до ES10, и ожидаемо валится с ошибкой


    Начиная с редакции ES10, круглые скобки можно опустить и catch станет как две капли воды похож на try.



    Мой Chrome уже обновился до ES10, а местами и до Stage 3. Дальше скриншоты будут из Chrome


    исходный код
    function isValidJSON(text) {
      try {
        JSON.parse(text);
        return true;
      } catch { // без аргумента
        return false;
      }
    }

     
     


    Доступ к описанию символьной ссылки


    https://tc39.github.io/proposal-Symbol-description/


    Описание символьной ссылки можно косвенно получить методом toString():


    const symbol_link = Symbol("Symbol description")
    String(symbol_link) // "Symbol(Symbol description)"

    Начиная с ES10 у символов появилось свойство description, доступное только для чтения. Оно позволяет без всяких танцев с бубном получить описание символа:


    symbol_link.description
    // "Symbol description"

    В случае если описание не задано, вернётся — undefined:


    const without_description_symbol_link = Symbol()
    without_description_symbol_link.description
    // undefined
    
    const empty_description_symbol_link = Symbol('')
    empty_description_symbol_link.description
    // ""

     
     


    Строки EcmaScript совместимые с JSON


    https://github.com/tc39/proposal-json-superset


    EcmaScript до десятой редакции утверждает, что JSON является подмножеством JSON.parse, но это неверно.


    JSON строки могут содержать неэкранированные символы разделителей линий U+2028 LINE SEPARATOR и абзацев U+2029 PARAGRAPH SEPARATOR.


    Строки ECMAScript до десятой версии — нет.


    Если в Edge вызвать eval() со строкой "\u2029",
    он ведёт себя так, словно мы сделали перенос строки — прямо посреди кода:



     


    C ES10 строками — всё в порядке:



     
     


    Доработка прототипного метода .toString()


    http://tc39.github.io/Function-prototype-toString-revision/


    Цели изменений
    • убрать обратно несовместимое требование:

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

    • уточнить «функционально эквивалентное» требование;


    • стандартизировать строковое представление встроенных функций и хост-объектов;


    • уточнить требования к представлению на основе «фактических характеристик» объекта;


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


    • для функций, определенных с использованием кода ECMAScript, toString должен возвращать фрагмент исходного текста от начала первого токена до конца последнего токена, соответствующего соответствующей грамматической конструкции;


    • для встроенных функциональных объектов toStringне должны возвращать ничего, кроме NativeFunction;


    • для вызываемых объектов, которые не были определены с использованием кода ECMAScript, toString необходимо вернуть NativeFunction;


    • для функций, создаваемых динамически (конструкторы функции или генератора) toString, должен синтезировать исходный текст;


    • для всех других объектов, toString должен бросить TypeError исключение.



    // Пользовательская функция
    function () { console.log('My Function!'); }.toString();
    // function () { console.log('My Function!'); }
    
    // Метод встроенного объекта объект
    Number.parseInt.toString();
    // function parseInt() { [native code] }
    
    // Функция с привязкой контекста
    function () { }.bind(0).toString();
    // function () { [native code] }
    
    // Встроенные вызываемые функциональный объекты
    Symbol.toString();
    // function Symbol() { [native code] }
    
    // Динамически создаваемый функциональный объект
    Function().toString();
    // function anonymous() {}
    
    // Динамически создаваемый функциональный объект-генератор
    function* () { }.toString();
    // function* () { }
    
    // .call теперь обязательно ждёт, в качестве аргумента, функцию
    Function.prototype.toString.call({});
    // Function.prototype.toString requires that 'this' be a Function"



     
     


    ֍ Stage 3


    Предложения вышедшие из статуса черновика, но ещё не вошедшие в финальную версию стандарта. 


    Приватные\статические\публичные методы\свойства\атрибуты у классов


    https://github.com/tc39/proposal-class-fields
    https://github.com/tc39/proposal-private-methods
    https://github.com/tc39/proposal-static-class-features


    В некоторых языках есть договорённость, называть приватные методы через видимый пробел ( «_» — такая_штука, ты можешь знать этот знак под неверным названием — нижнее подчёркивание).


    Например так:


    <?php
    class AdultContent {
        private $_age = 0;
        private $_content = '…is dummy example content (•)(•) —3 (.)(.) only for adults…';
        function __construct($age) {
            $this->_age = $age;
        }
        function __get($name) {
            if($name === 'content') {
                return " (age: ".$this->_age.") → ".$this->_getContent()."\r\n";
            }
            else {
                return 'without info';
            }
        }
        private function _getContent() {
            if($this->_contentIsAllowed()) {
                return $this->_content;
            }
            return 'Sorry. Content not for you.';
        }
        private function _contentIsAllowed() {
            return $this->_age >= 18;
        }
        function __toString() {
            return $this->content;
        }
    }
    echo "<pre>";
    
    echo strval(new AdultContent(10));
    //  (age: 10) →  Sorry. Content not for you
    
    echo strval(new AdultContent(25));
    // (age: 25) →  …is dummy example content (•)(•) —3 only for adults…
    
    $ObjectAdultContent = new AdultContent(32);
    echo $ObjectAdultContent->content;
    // (age: 32) →  …is dummy example content (•)(•) —3 only for adults…
    ?>
    

    Напомню — это только договорённость. Ничто не мешает использовать префикс для других целей, использовать другой префикс, или не использовать вовсе.


    Лично мне импонирует идея использовать видмый пробел в качестве префикса для функций, возвращающих this. Так их можно объединять в цепочку вызовов.


    Разработчики спецификации EcmaScript пошли дальше и сделали префикс-октоторп ( «#» —решётка, хеш ) частью синтаксиса.


    Предыдущий пример на ES10 можно переписать следующим образом:


    export default class AdultContent {
    
      // Приватные атрибуты класса
      #age = 0
      #adult_content = '…is dummy example content (•)(•) —3 (.)(.) only for adults…'
    
      constructor(age) {
        this.#setAge(age)
      }
    
      // Статический приватный метод
      static #userIsAdult(age) {
        return age > 18
      }
    
      // Публичное свойство
      get content () {
        return `(age: ${this.#age}) → ` + this.#allowed_content
      }
    
      // Приватное свойство
      get #allowed_content() {
          if(AdultContent.userIsAdult(this.age)){
            return this.#adult_content
        }
        else {
            return 'Sorry. Content not for you.'
        }
      }
    
      // Приватный метод
      #setAge(age) {
          this.#age = age
      }
    
      toString () {
        return this.#content
      }
    }
    
    const AdultContentForKid = new AdultContent(10)
    
    console.log(String(AdultContentForKid))
    // (age: 10) → Sorry. Content not for you.
    
    console.log(AdultContentForKid.content)
    // (age: 10) → Sorry. Content not for you.
    
    const AdultContentForAdult = new AdultContent(25)
    
    console.log(String(AdultContentForAdult))
    // (age: 25) → …is dummy example content (•)(•) —3 (.)(.) only for adults…
    
    console.log(AdultContentForAdult.content)
    // (age: 25) → …is dummy example content (•)(•) —3 (.)(.) only for adults…
    

    Пример излишне усложнён для демонстрации приватных свойств, методов и атрибутов разом. Но в целом JS — радует глаз своей лаконичностью по сравнению с PHP вариантом. Никаких тебе private function _..., ни точек с запятой в конце строки, и точка вместо «->» для перехода вглубь объекта.


    Геттеры именованные. Для динамических имён — прокси-объекты.


    Вроде бы мелочи, но после перехода на JS, всё меньше желания возвращаться к PHP.


    К слову приватные акцессоры доступны только с Babel 7.3.0 и старше.


    На момент написания статьи, самая свежая версия по версии npmjs.com — 7.2.2


    Ждём в Stage 4!


     
     


    Шебанг грамматика


    https://github.com/tc39/proposal-hashbang


    Хешбэнг — знакомый юниксоидам способ указать интерпретатор для исполняемого файла:


    #!/usr/bin/env node
    // в скрипте
    'use strict';
    console.log(1);

    #!/usr/bin/env node
    // в модуле
    export {};
    console.log(1);

    в данный момент, на подобный фортель, Chrome выбрасывает SyntaxError: Invalid or&nbsp;unexpected token
     
     


    Большие числа с BigInt


    https://github.com/tc39/proposal-bigint


    поддержка браузерами

    Поддержка браузерами примитива BigInt()


    Максимальное целое число, которое можно безопасно использовать в JavaScript (2⁵³ — 1):


    console.log(Number.MAX_SAFE_INTEGER)
    // 9007199254740991

    BigInt нужен для использования чисел произвольной точности.


    Объявляется этот тип несколькими способами:


    // используя 'n' постфикс в конце более длинных чисел
    910000000000000100500n
    // 910000000000000100500n
    
    // напрямую передав в конструктор примитива BigInt() без постфикса
    BigInt( 910000000000000200500 )
    // 910000000000000200500n
    
    // или передав строку в тот-же конструктор
    BigInt( "910000000000000300500" )
    // 910000000000000300500n
    
    // пример очень большого числа длиной 1642 знака
    BigInt( "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" )
    \\ 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999n

    Это новый примитивный тип:


    typeof 123;
    // → 'number'
    typeof 123n;
    // → 'bigint'

    Его можно сравнивать с обычными числами:


    42n === BigInt(42);
    // → true
    42n == 42;
    // → true

    Но математические операции нужно проводить в пределах одного типа:


    20000000000000n/20n
    // 1000000000000n
    
    20000000000000n/20
    // Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
    

    Поддерживается унарный минус, унарный плюс возвращает ошибку:


     -2n
     // -2n
    
     +2n
     // Uncaught TypeError: Cannot convert a BigInt value to a number
    

     


    globalThis — новый способ доступа к глобальному контексту


    https://github.com/tc39/proposal-global


    работает в Chrome


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


    var getGlobal = function () {
        if (typeof self !== 'undefined') { return self; }
        if (typeof window !== 'undefined') { return window; }
        if (typeof global !== 'undefined') { return global; }
        throw new Error('unable to locate global object');
    };

    И даже такой вариант не гарантировал, что всё точно будет работать.


    globalThis — общий для всех платформ способ доступа к глобальной области видимости:


    // Обращение к глобальному конструктору массива
    globalThis.Array(1,2,3)
    // [1, 2, 3]
    
    // Запись собственных данных в глобальную область видимости
    globalThis.myGLobalSettings = {
        it_is_cool: true
    }
    
    // Чтение собственных данных из глобальной области видимости
    globalThis.myGLobalSettings
    // {it_is_cool: true}

     
     


    Динамический import(dynamic)


    https://github.com/tc39/proposal-dynamic-import


    поддержка браузерами

    Поддержка браузерами динамических импортов


    Хотелось переменные в строках импорта‽ С динамическими импортами это стало возможно:


    import(`./language-packs/${navigator.language}.js`)

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


    Поэтому загружать модули можно — отложенно, когда это необходимо:


    element.addEventListener('click', async () => {
        // можно использовать await синтаксис для промиса
        const module = await import(`./events_scripts/supperButtonClickEvent.js`)
        module.clickEvent()
    })

    Синтаксически, это выглядит как вызов функции import(), но не наследуется от Function.prototype, а значит вызвать через call или apply — не удастся:


    import.call("example this", "argument")
    // Uncaught SyntaxError: Unexpected identifier

     
     


    import.meta — мета-информация о загружаемом модуле.


    https://github.com/tc39/proposal-import-meta


    работает в Chrome


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


    console.log(import.meta);
    // { url: "file:///home/user/my-module.js" }

     
     


    Создание объекта методом Object.fromEntries()


    https://github.com/tc39/proposal-object-from-entries


    Аналог _.fromPairs из lodash:


    Object.fromEntries([['key_1', 1], ['key_2', 2]])
    // {key_1: 1; key_2: 2}

     
     


    Фикс метода JSON.stringify()


    https://github.com/tc39/proposal-well-formed-stringify


    В разделе 8.1 RFC 8259 требуется, чтобы текст JSON, обмениваемый за пределами замкнутой экосистемы, кодировался с использованием UTF-8, но JSON.stringify может возвращать строки, содержащие кодовые точки, которые не представлены в UTF-8 (в частности, суррогатные кодовые точки от U+D800 до U+DFFF)


    Так строка \uDF06\uD834 после обработки JSON.stringify() превращается в \\udf06\\ud834:


    /* Непарные суррогатные единицы будут сериализованы с экранированием последовательностей */
    JSON.stringify('\uDF06\uD834')
    '"\\udf06\\ud834"'
    JSON.stringify('\uDEAD')
    '"\\udead"'

    Такого быть не должно, и новая спецификация это исправляет. Edge и Chrome уже обновились.


     
     


    Устаревшие возможности RegExp


    https://github.com/tc39/proposal-regexp-legacy-features


    Спецификация для устаревших функций RegExp, вроде RegExp.$1, и RegExp.prototype.compile() метода.


     
     


    Прототипные методы строк .trimStart() и .trimEnd()


    https://github.com/tc39/proposal-string-left-right-trim


    работает в Chrome


    По аналогии с методами .padStart() и .padEnd(), обрезают пробельные символы в начале и конце строки соответственно:


    const one = "      hello and let ";
    const two = "us begin.        ";
    console.log( one.trimStart() + two.trimEnd() )
    // "hello and let us begin."

     
     


    .matchAll() — новый прототипный метод строк.


    https://github.com/tc39/proposal-string-matchall


    работает в Chrome


    Работает как метод .match() с включенным флагом g, но возвращает итератор:


    const string_for_searh = 'olololo'
    
    // Вернёт первое вхождение с дополнительной информацией о нём
    string_for_searh.match(/o/)
    // ["o", index: 0, input: "olololo", groups: undefined]
    
    //Вернёт массив всех вхождений без дополнительной информации
    string_for_searh.match(/o/g)
    // ["o", "o", "o", "o"]
    
    // Вернёт итератор
    string_for_searh.matchAll(/o/)
    // {_r: /o/g, _s: "olololo"}
    
    // Итератор возвращает каждое последующее вхождение с подробной информацией,
    // как если бы мы использовали .match без глобального флага
    for(const item of string_for_searh.matchAll(/o/)) {
      console.log(item)
    }
    // ["o", index: 0, input: "olololo", groups: undefined]
    // ["o", index: 2, input: "olololo", groups: undefined]
    // ["o", index: 4, input: "olololo", groups: undefined]
    // ["o", index: 6, input: "olololo", groups: undefined]

    Аргумент должен быть регулярным выражением, иначе будет выброшено исключение:


    'olololo'.matchAll('o')
    // Uncaught TypeError: o is not a regexp!

     
     


    Одномерные массивы с .flat() и .flatMap()


    https://github.com/tc39/proposal-flatMap


    работает в Chrome


    Массив обзавёлся прототипами .flat() и .flatMap(), которые в целом похожи на реализации в lodash, но всё же имеют некоторые отличия. Необязательный аргумент — устанавливает максимальную глубину обхода дерева:


    const deep_deep_array = [
      '≥0 — первый уровень',
      [
        '≥1 — второй уровень',
        [
          '≥2 — третий уровень',
          [
            '≥3 — четвёртый уровень',
            [
              '≥4 — пятый уровень'
            ]
          ]
        ]
      ]
    ]
    
    // 0 — вернёт массив без изменений
    deep_deep_array.flat(0)
    //  ["≥0 — первый уровень", Array(2)]
    
    // 1 — глубина по умолчанию
    deep_deep_array.flat()
    //  ["первый уровень", "второй уровень", Array(2)]
    
    deep_deep_array.flat(2)
    //  ["первый уровень", "второй уровень", "третий уровень", Array(2)]
    
    deep_deep_array.flat(100500)
    // ["первый уровень", "второй уровень", "третий уровень", "четвёртый уровень", "пятый уровень"]

    .flatMap() эквивалентен последовательному вызову .map().flat(). Функция обратного вызова, передаваемая в метод, должна возвращать массив который станет частью общего плоского массива:


    ['Hello', 'World'].flatMap(word => [...word])
    // ["H", "e", "l", "l", "o", "W", "o", "r", "l", "d"]

    С использованием только .flat() и .map(), пример можно переписать так:


     ['Hello', 'World'].map(word => [...word]).flat()
    // ["H", "e", "l", "l", "o", "W", "o", "r", "l", "d"]

    Также нужно учитывать, что у .flatMap() в отличии от .flat() нет настроек глубины обхода. А значит склеен будет только первый уровень.




     
     


    Итоги


    Stage 4 привнёс скорее косметические изменения. Интерес представляет Stage 3. Большинство из предложений в Chrome уже реализованы, за исключением пожалуй Object.fromEntries(), наличие которого не критично, а приватные свойства очень ждём.


     




     


    Исправления в статье


     
    Если заметил в статье неточность, ошибку или есть чем дополнить — ты можешь написать мне личное сообщение, а лучше самому воспользоваться репозиторием статьи https://github.com/KasperGreen/es10. За активный вклад, награжу жёлтым магнитом-медалью с КДПВ.


    Материалы по теме


    Материал на английском Актуальная версия стандарта Ecma-262


    Материал на английском Черновик следующей версии стандарта Ecma-262


    ECMAScript


    Новые #приватные поля классов в JavaScript


    Статья на Хабре Обзор возможностей стандартов ES7, ES8 и ES9


    Шебанг


    Статья на Хабре BigInt — длинная арифметика в JavaScript


    Статья на Хабре Путь JavaScript модуля


    Материал на английском Почему не private x


    Статья на Хабре ECMAScript Proposal: Array.prototype.{flat,flatMap}




     
     


    Альтернативный вариант КДПВ с жёлтым магнитом от elfafeya.art
           Автор фото: kasper.green; Жёлтый магнит: elfafeya.art & kasper.green

    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

    Самая ожидаемая фича:

    Поделиться публикацией

    Комментарии 58

      0

      За динамические импорты много проголосовало. Ох, нехороший пример приводят в его пользу. Чувствую, ждут нас еще code injection...


      Кстати, а чем он будет отличаться от старого доброго require?

      +8
      Приватные\статические\публичные методы\свойства\атрибуты у классов
      Полезная, конечно фича, но зачем её было делать настолько через пень… Вместо того, чтобы добавить private/public как у всех, ввели особый префикс к именам, который нужно указывать не только при объявлении, но и при вызове. То есть решил заприватить или расприватить свойство, иди перелопать все места, где оно используется…
        –3

        Или нажмите shift+f6 в webstorm.

          +4
          Автоматизированный костыль не перестаёт быть костылём.
          Ну и работает для чистого JS мягко говоря не всегда.
          +3
          Приватное свойство на то и приватное, что используется в рамках одного класса, а значит и файла. Много где лопатить не придется по определению
            0

            Это если вы приватное делаете публичным. А если наоборот — то придется

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

            Вопрос "почему не private" настолько популярный, что в FAQ к спеке на него есть ответ.

              0
              Я так и не осилил понять, почему не private при объявлении. Понял почему не @, _ и.т.д.
            –1
            Поддерживаю. # — ужасная идея. Лучше не иметь приватных полей, чем иметь их такой ценой.
              0

              Когда вы решили сделать метод приватным, придётся пойти и перелопатить всё за пределами его класса. И октоторп здесь ни при чём, для private будет аналогично.

              +5

              Кто-то ещё использует самые названия вида es7-10, вам самим то удобно так? Это же нужно вспомнить что es6 = es2015, значит es10 = es2019. Сложно же, да и если мне не изменяет память официально был только es6, а потом они сменили название и теперь удобно указывают год.

                0

                Вы правы, они теперь только скромно помечают номер редакции.


                Но десятая редакция настолько круглая, что захотелось акцентировать на этом внимание. Помнить нужно было, что редакция = год \d^+1. Но со следующей редакции всё станет чуточку сложнее. Возможно вы правы и пора забыть об обычных порядковых номерах версий и перейти на порядковые со смещением +2009.

                0
                del
                  +3
                  Крайняя версия на npmjs.com

                  ПОСЛЕДНЯЯ

                  знакомый юниксойдам

                  юниксоидам
                  +1
                  Выскажу возможно непопулярное мнение, но на мой взгляд, приватные свойства (поля/методы) — крайне сомнительная идея, которой не место в языке.

                  TL;DR
                  Бессмысленное усложнения языка. Нужны приватные свойства — вам в TS.

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

                  Большинство новых фич языка начиная с ES6 были аккуратными правками к имеющейся модели языка и надстройками над ней.
                  Но не приватные свойства — они совершенно не вписываются в имеющуюся модель поиска свойств и никак не доступны для рефлексии (что ещё более усугубляет первый пункт).
                  Т. о. это такая языковая фича, которая с т. з. остального языка работает «на магии» и потому требует дополнительных усилий для своего понимания — т. е. усложняет язык.

                  И мне лично совершенно непонятно зачем нужно это усложнение.
                  Я понимаю ценность разделения на public/protected/private (особенно в больших проектах), но на практике обычно соглашения по именованию хватает с лихвой.
                  Более того, если по какой-то причине вам кровь из носу нужны protected/private-свойства в вашем JS-проекте, то они уже есть — в TypeScript.
                  И сделаны они там не в пример лучше (не говоря уж о том, что идут с дополнительными плюшками, вроде интерфейсов).

                  P.S.
                  Все вышенаписанное не претендует на истину в последней инстанции.
                  Буду рад аргументированной дискуссии.
                    +1
                    Но… приватные свойства — они совершенно не вписываются в имеющуюся модель поиска свойств и никак не доступны для рефлексии

                    По задумке автора кода тайное должно быть скрыто и недоступно для модификации (SOLID — the Open-Closed Principle). Вседозволенность провоцирует использовать инструменты неправильно.
                    Для рефлекшна это должно быть доступно (не проверял, но надеюсь, ибо так работает во многих других языках), но программист должен чувствовать себя грязным после этого действа (=

                    мне лично совершенно непонятно зачем нужно это усложнение

                    Чтобы те, кому это нужно, не извращались, эмулируя приватность через замыкания.

                    Я понимаю ценность разделения на public/protected/private (особенно в больших проектах), но на практике обычно соглашения по именованию хватает с лихвой.

                    Чтобы контролировать эти соглашения автоматически. Если вам это очень-очень не нужно, почему бы этой возможностью просто не пользоваться?
                      0
                      Чтобы контролировать эти соглашения автоматически.
                      Чтобы те, кому это нужно, не извращались, эмулируя приватность через замыкания.
                      Я прекрасно понимаю, какие преимущества имеет поддержка разграничения доступа на уровне среды выполнения перед простыми соглашениями.
                      Но в современном JS-мире вам не нужно извращаться через замыкания, symbol'ы, proxy, weak map'ы или как-то ещё — у нас есть TypeScript.
                      Так что ценность добавления функциональности в сам JS очень сомнительна.

                      Если вам это очень-очень не нужно, почему бы этой возможностью просто не пользоваться?
                      Я не говорил, что не не нужна эта возможность. Я утверждаю, что она вредна (по крайней мере в текущем виде), т. к. она ухудшает дизайн языка.

                      Для рефлекшна это должно быть доступно
                      Оно недоступно, ни в каком виде. И пока нет никаких предпосылок к изменению ситуации.

                        +3
                        у нас есть TypeScript

                        Мне это не кажется хорошим поводом не развивать JS.

                        Я утверждаю, что она вредна… она ухудшает дизайн языка.

                        Язык становится более выразительным, обретает новые возможности, в чем же ухудшение?
                          0
                          в чем же ухудшение?
                          Я же написал в самом первом комментарии:
                          [приватные свойства] совершенно не вписываются в имеющуюся модель поиска свойств
                          это такая языковая фича, которая с т. з. остального языка работает «на магии»

                          Мне это не кажется хорошим поводом не развивать JS.
                          Тут дело в том, зачем мы (кхм, человечество) развиваем язык — не ради «новых возможностей», а для более эффективного решения наших проблем.
                          Проблема формулирования строгих ООП-контрактов в JS давно и успешно решена TS'ом, и эта проблема не требует повторного решения.
                          Однако же TC39 вместе с разработчиками браузеров угрохали на это изрядное количество человеко-часов.
                            +1
                            Я же написал в самом первом комментарии

                            Там нет объективного обоснования этому субъективному взгляду на то, каким должен быть язык.

                            это такая языковая фича, которая с т. з. остального языка работает «на магии»

                            Замыкания тоже «на магии» работают и рефлекшну не поддаются.

                            зачем мы… развиваем язык — не ради «новых возможностей», а для более эффективного решения наших проблем.

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

                            Проблема формулирования строгих ООП-контрактов в JS давно и успешно решена TS'ом

                            TS требует препроцессинга, это не всех устраивает.
                              0
                              Там нет объективного обоснования этому субъективному взгляду на то, каким должен быть язык.
                              С максимально компактной и непротиворечивой моделью. Вполне объективный критерий.

                              Замыкания тоже «на магии» работают и рефлекшну не поддаются.
                              Да, но нет.
                              1) Замыкания — одна из ключевых концепций языка (как, например, цепочка прототипов). Эдак можно ещё проще сказать — весь язык работает «на магии», так что можно добавлять в него любые новые конструкции.
                              2) Замыкания — существующий (и очень простой) механизм, приватные свойства — значительное (и достаточно нетривиальное) изменение в другом базовом механизме (properties lookup). Если завтра в стандарт внесут новый тип замыканий, который работает совсем не так, как текущие замыкания, это тоже будет усложнением модели языка (и скорее всего тоже неоправданным).

                              требует препроцессинга, это не всех устраивает.
                              Очень спорное утверждение, в мире современной JS-разработки с его Babel/TypeScript/CoffeeScript/etc.
                              Использовать # в JS без препроцессинга в реальных проектах всё равно будет невозможно ещё N лет.
                              Ну то есть я не буду спорить, что наверное существуют люди, которые принципиально пишут на чистом JS и при этом остро нуждаются в строгой инкапсуляции приватных свойств, но мне кажется, что их доля в общей массе JS-разработчиков исчезающе мала.
                                +1
                                С максимально компактной и непротиворечивой моделью.

                                Компактность — это характиристика, которая сама по себе ничего не значит, в отличии от выразительности.
                                Противоречия не должно быть.

                                Замыкания — существующий (и очень простой) механизм

                                Не об эту ли простоту новички ломают голову? Реализация лексической области видимости и замыканий — это источник огромного количества багов в JS из-за потери контекста, неуправляемого тотального экспорта переменных и прочее. Поэтому — нет, не простой.
                                А то, что он существующий — что за аргумент? Что он должен показывать?
                                Использовать # в JS без препроцессинга в реальных проектах всё равно будет невозможно ещё N лет.

                                Если не внедрять новые стандарты де юре, то де факто они не станут никогда.
                                  0
                                  Компактность — это характиристика, которая сама по себе ничего не значит, в отличии от выразительности.
                                  Компактность обеспечивают простоту понимания языка (меньше надо в голове держать). А вот выразительность — крайне субъективная характеристика. Мне вот не кажется, что замена _ на # в коде как-то изменить его выразительность.

                                  Не об эту ли простоту новички ломают голову?
                                  Ну, теперь они ещё будут ломать голову об properties lookup и то, как он сочетается с приватными свойствами. :)
                                  Серьёзно — замыкания концептуально очень простая штука, к тому же реализованная в JS точно так же, как в других языках. Ни того, ни другого, нельзя сказать про приватные свойства.

                                  огромного количества багов в JS
                                  потери контекста, неуправляемого тотального экспорта переменных и прочее
                                  Было бы очень интересно (без сарказма) увидеть конкретные реальные примеры.

                                  что он существующий — что за аргумент? Что он должен показывать?
                                  Изначально я писал об усложнении модели языка [относительно имеющейся]. Говорить о том, что уже существующие базовые механизмы языка, на мой взгляд, бессмысленно.
                                    +1
                                    Компактность обеспечивают простоту понимания языка (меньше надо в голове держать).

                                    Это совсем не факт, если это малое состоит сплошь из неочевидностей.
                                    Например class и arrow functions пусть и «усложняют» синтаксис, но исправляют (в смысле дают альтернативу) очевидные архитектурные косяки, существовавшие в языке изначально.

                                    Мне вот не кажется, что замена _ на # в коде как-то изменить его выразительность.

                                    Соглашение о префиксе "_" не поддерживается рантаймом. А «решетка» — это замена замкнутым, приватным по факту, переменным. Так что вполне повыщает выразительность языка, позволяя явно недвузначно выражать свои намерения специальными конструкциями, а не стандартными хаками из подручных материалов.
                                    теперь они ещё будут ломать голову об properties lookup и то, как он сочетается с приватными свойствами

                                    Приватные переменные на то и приватные, чтобы их извне не трогали.

                                    замыкания концептуально очень простая штука, к тому же реализованная в JS точно так же, как в других языках

                                    Ну, например, в C++ она реализована лучше, вынуждая явно объявлять способ захвата.

                                    Было бы очень интересно (без сарказма) увидеть конкретные реальные примеры.

                                    Очень популярная и неочевидная для новичка конструкция:
                                    const self = this;

                                    А уж «методы», зовущиеся от глобального объекта — это постоянная боль.

                                    Изначально я писал об усложнении модели языка

                                    Усложнение (в плане обогащения синтаксиса и семантики) само по себе — не недостаток.
                                    Здесь, как мне кажется, ключевым может быть доказательство бесполезности, а то и вреда вводимой конструкции.
                                      0
                                      class и arrow functions пусть и «усложняют» синтаксис
                                      Ничего они не усложняют, они примитивный синтаксический сахар над существующей моделью языка (за очень редкими исключениями).

                                      const self = this;
                                      «методы», зовущиеся от глобального объекта
                                      Непонятно, каким образом всё это стало проблемой замыканий.

                                      в C++ она реализована лучше
                                      Я не о «лучше/хуже», я о том, что разобравшись один раз с замыканиями в Python/Ruby/etc, в JS не встретишь ничего нового.
                                      Синтаксис же # порядком отличается от аналогов.
                                      (Замыкания именно в C++ обсуждать не готов.)
                                        +1
                                        они примитивный синтаксический сахар над существующей моделью языка

                                        Что мешает сделать приватные переменные таким же примитивным сахаром над замыканиями?)

                                        Непонятно, каким образом всё это стало проблемой замыканий.

                                        Импорт переменных из внешней лексической области видимости никак не ограничивается. А контекст, в виде self, часто именно с помощью этой «фичи» просовывается в функции.
                                        Легко ошибиться, непросто понять.

                                        Синтаксис же # порядком отличается от аналогов.

                                        Синтаксис не сложный (тот же "_" использовать привычно), а семантика всем знакома. Просто теперь это правило еще будет контролироваться рантаймом.
                                          0
                                          Что мешает сделать приватные переменные таким же примитивным сахаром над замыканиями?)
                                          То, что они им не являются. Невозможно рассматривать # как синтаксический сахар над любыми имеющимися паттернам (будь то замыкания, weakmap'ы или что ещё), никакая подобная «модель» для # не опишет все их особенности поведения.

                                          Синтаксис не сложный (тот же "_" использовать привычно), а семантика всем знакома.
                                          Весьма опасное заблуждения, поскольку семантика сильно отличается. Попробуйте «просто заменить» _ на # в таком классе:
                                          class Foo {
                                              constructor(x, y) { 
                                                  this._x = x;
                                                  this._y = y;
                                              }
                                              valueOf() {
                                                  let value = 0;	
                                                  for (let prop in this) { 
                                                      value += this[prop]; 
                                                  }
                                                  return value;
                                              }
                                          }
                                          
                                          foo = new Foo(1, 2);
                                          foo.valueOf();

                                          Самое прелестное, что после такой замены у вас ничего не упадёт — но и работать не будет.
                                            0
                                            Что мешает сделать
                                            То, что они им не являются.

                                            Мы сейчас рискуем зациклиться.

                                            Попробуйте «просто заменить» _ на # в таком классе

                                            То, что это не работает в конкретной имплементации не делает саму концепцию приватных полей плохой. Рефлекшн должен поддерживать приватные поля, я об этом еще где-то в начале треда говорил.
                                              +1
                                              Что мешает сделать приватные переменные таким же примитивным сахаром над замыканиями?)
                                              Возможно, я неправильно понял изначальный вопрос.
                                              Почему нельзя было реализовать #-синтаксис так, чтобы он был простым синтаксическим сахаром над замыканиями?
                                              Ну, к примеру, потому что на замыканиях невозможно организовать доступ к приватным полям другого инстанса класса (подозреваю, что есть и другие ограничения).
                                              (пример)
                                              class Foo {
                                                  #x;
                                                  constructor(x) {
                                                      this.#x = x;
                                                  }
                                                  equals(other) {
                                                      return this.#x === other.#x;
                                                  }
                                              }


                                              С другой стороны, у реализаций на weakmap'ах и symbol'ах вышеописанной проблемы нет, и в целом мне кажется, что можно было реализовать #-синтаксис без введения новой механики в языке.
                                              Почему оно (уже) сделано как сделано — вопрос не ко мне.

                                              То, что это не работает в конкретной имплементации не делает саму концепцию приватных полей плохой.
                                              Нет, но это делает её confusing, а это в свою очередь — делает её плохой не очень хорошей. :)
                                              И рефлексия тут уже не причём, она не особо поможет в данном конкретном примере.
                                                0
                                                А так можно?

                                                class First {
                                                  #private_field = 'olololo'
                                                }
                                                class Second extends First {
                                                  someMethod = () => {
                                                    const { #private_field } = this
                                                    console.log(#private_field)
                                                  }
                                                }
                                                
                                                  0
                                                  Честно говоря, я плохо понимаю суть примера, но работать он не будет. (:

                                                  1. Приватные свойства недоступны в потомках (никакого protected не предусмотрено; пока что?..).
                                                  2. Насколько я понимаю, к приватным свойствам можно обращаться исключительно как this.#prop; соответственно, с деструктурированием они никак не сочетаются.
                                                  3. Объявить переменную #var невозможно, т. к. # — невалидный синтаксис в JS (собственно, это одна из причин, почему такой синтаксис был выбран для приватных свойств).
                                                    0
                                                    Кажется, я понял замысел. Предполагалось что-то вроде такого?
                                                    class Foo {
                                                        _x = 1;
                                                        destructureX() {
                                                            const { _x: x } = this;
                                                            return x;
                                                        }
                                                    }
                                                    
                                                    new Foo().destructureX();  // => 1
                                                      0

                                                      Да. Деструктуризация в первую очередь интересовала.


                                                      Заинтересовался какой же префикс хотят использовать для остальных случаев — оказалось всё прозаично.


                                                      Consider protected, abstract, and friend #25


                                                      Открыл для себя friend и private для тех кому нужно.

                                                        0
                                                        Consider protected, abstract, and friend #25
                                                        И станет JS наконец-то походить на язык, «в честь которого» назван. %)
                                                        abstract class Foo {
                                                          protected abstract static async #bar(a, b); 
                                                        }
                                                        


                                                        FGJ, это ещё даже не proposal, так что может, и не доживём ещё. Сами декораторы вон уже третий год делают, а они всё ещё stage 2.
                                                          0

                                                          Декораторами не первый год пользуюсь. Странно, что до сих пор в stage 2


                                                          Ja Va Script

                                                            0
                                                            Да, к моему удивлению, несмотря на состояние и поддержку, декораторы весьма популярны.
                                                            Видимо, сказывается бесстрашие JS-разработчиков. :)
                                                      +1
                                                      Руководствуюсь очевидным правилом «просто заменяем _ на #» легко получить #-аналог:
                                                      class Foo {
                                                          #x = 1;
                                                          destructureX() {
                                                              const { #x: x } = this;
                                                              return x;
                                                          }
                                                      }


                                                      Однако узнать, рабочий ли это вариант, увы, не суждено. :D




                                                      P. S. Баг в трекере заведён, всё под контролем.
                                                      0
                                                      Вы правы, на замыканиях это будет неудобно в ряде моментов. А без них нужна гарантия родственности типов, где утиная типизация в JS не особо подходит.
                                              +1
                                              Усложнение (в плане обогащения синтаксиса и семантики) само по себе — не недостаток.
                                              Мне кажется, тут есть некоторое различие — между «обогащением синтаксиса» и «усложнением модели».

                                              Развитие синтаксиса более выразительными конструкциями действительно благо — хороший пример те же arrow functions.
                                              Они не привносят в язык ничего принципиально нового (т. о. достаточно пятиминутного экскурса, чтобы понять о чём речь), но радикально упрощают написание кода, избавляя от необходимости постоянно писать .bind(this) или self = this.

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

                                              Синтаксис # работает очень нетипично для JS (фактически в обход нормального property lookup) и имеет массу подводных камней — нельзя создавать приватные свойства без предварительного объявления (что вообще дикость для динамического JS), нельзя объявлять методы вне класса (через F.prototype.m = ...) и так далее.

                                              Вот простейший пример, который лично у каждый раз вызывает некоторую оторопь:

                                              Замазал пару строк, чтобы сохранить интригу.
                                              Разумеется там
                                              foo = new Foo(20);
                                              foo['#x'] = 10;
                                              

                                              Мой посыл в целом заключается в том, что все эти «особенности» перевешивают крайне сомнительные его преимущества (ниже я писал о том, что # выглядит игрушкой по сравнению с одним private в TS).
                                                0
                                                Разумеется там

                                                Манкипатчинг)
                                                Я бы хотел, чтобы для 'use strict2' здесь вылетала ошибка.

                                                Соглашусь с вами, что под грузом обратной совместимости и тяжелой наркомании разработчиков языка данный модификатор требует некоторого внимания. Приватные члены — это не сложная концепция и выглядит даже логично, если выделять «решетку» именно как модификатор, а не часть имени члена.
                                                  0
                                                  Я бы хотел, чтобы для 'use strict2' здесь вылетала ошибка.
                                                  То есть ошибка должна вылетать для любого target[prop] = value;?
                                                  0
                                                  Спасибо за комментарий. Для меня было не очевидно, что приватные свойства нужно объявлять заранее.
                                                    +1
                                                    Не за что, для меня тоже это было абсолютно не очевидно. :)
                                                    Но надо отдать должно разработчикам V8 за понятные ошибки.
                                                    class Foo {
                                                        constructor(x) { this.#x = x; }
                                                    }
                                                    
                                                    // Uncaught SyntaxError: Undefined private field #x: must be declared in an enclosing class
                                        0
                                        КМК приватные штучечки не про нас. Пусть ими пользуются большие команды из сотен человек. Если лично нам они не нужны, это не повод тормозить остальных.

                                        TS — не панацея. Также как и ColaScript, Dart, CofeeScript… — это язык транспилируемый в JavaScript.

                                        TS — это не стандарт, а побочный продукт Microsoft. Он может перестать быть нужен мелкомягким. Конечно это не факт, но потенциальная вероятность.

                                        TS — язык строго типизированный. Это ни хорошо, ни плохо. Это другой способ мышления. Так же как ООП не хуже функционального подхода, они просто разные.
                                          +1
                                          КМК приватные штучечки не про нас. Пусть ими пользуются большие команды из сотен человек.
                                          TS — не панацея.
                                          У меня есть непосредственный опыт работы в команде из нескольких сот человек на SPA-проекте в несколько миллионов LOC (поэтому мне кажется, что я представляю о чём говорю).
                                          Ничто не панацея, само собой, но TS даёт гораздо, гораздо более мощные средства инкапсуляции и формулирования контрактов, т. к. помимо private-/protected-модификаторов предоставляет интерфейсы, мощный синтаксис описания типов и многое другое. Даже один-единственный private в TS более гибкий, чем # в JS — хотя бы потому что позволяет описывать private constructors, что в JS невозможно.
                                          По сравнению со всем этим приватные свойства в JS выглядят просто игрушкой.

                                          TS — это не стандарт, а побочный продукт Microsoft. Он может перестать быть нужен мелкомягким.
                                          Согласен, это, пожалуй, самая большая его проблема.
                                          Но не нужно забывать, что (1) это opensource и (2) вокруг TS уже существует развитая экосистема со множеством участников (тот же Angular2+ от Google написан целиком на TS).

                                          TS — язык строго типизированный. Это ни хорошо, ни плохо.
                                          Позволю себе поправить: TS слабо типизирован, так же как и JS — но в противоположность ему, он статически (а не динамически) типизирован.

                                          Согласен что это разные парадигмы, имеющие свои плюсы и минусы.
                                          Но если мы говорим «у нас большие команды, большие проекты, нам нужно контролировать сложность», то статическая типизация TS является скорее преимуществом.
                                    0
                                    По задумке автора кода тайное должно быть скрыто и недоступно для модификации (SOLID — the Open-Closed Principle)
                                    Ну ладно, приписывать модификатор private к инкапсуляции — это распространенное заблуждение. Но вот к принципу открытости-закрытости — вы пробили новое дно. Он совершенно о другом.
                                  0
                                  .flatMap() не эквивалентен последовательному вызову .flat().map()

                                  Долго не мог понять, что не так с этой фразой. Потом дошло — .flatMap() эквивалентен последовательному вызову .map().flat(), так что фраза корректная, но сформулирована немного шиворот-навыворот. :)
                                    0

                                    Нет. Именно не эквивалентен. Последовательный вызов .flat().map() сделает массив плоским и пройдётся по нему функцией обратного вызова, а .flatMap() действует в обратном порядке, как .map().flat(). Сначала будет обход, а потом результаты станут плоскими, но без настроек вложенности, с обходом на один уровень.


                                    ['Hello', 'World'].flatMap(word => [...word])

                                    Этот пример можно переписать следующим образом:


                                    ['Hello', 'World'].map(word => [...word]).flat()
                                    
                                    // Подробнее:
                                    ['Hello', 'World']
                                    .map(word => [...word]) 
                                    // разобьём каждое слово на массив букв. В результате получим два массива
                                    // [ ["H", "e", "l", "l", "o"], ["W", "o", "r", "l", "d"]]
                                    .flat() // устраним вложенность
                                    // ["H", "e", "l", "l", "o", "W", "o", "r", "l", "d"]
                                      0
                                      Столько суматохи вокруг приватных свойств, а можно же было простые фабрики с замыканиями использовать
                                        0
                                        Ещё приватные свойства можно реализовать через прокси-объекты или через символьные ссылки.
                                        Цель предложения — стандартизировать синтаксис и заодно префикс.
                                          0
                                          Еще викмапы*

                                          «стандартизировать синтаксис» — нууу, я так понял что нет. Просто у кого-то влиятельного зачем-то припекло. С этим предложением было (и есть) не малый ряд проблем, зачем нужно было так ультимативно пропихивать его — морально не ясно.
                                        0
                                        «Самая ожидаемая фича:» — не хватает варианта «другое». У меня это опциональный чейнинг, пайплайны, паттерн-матчинг — инструменты, которые ощутимо упростят разработку. То что в этой ревизии добавили кажется незначительным.
                                          0

                                          Подразумевалась фича из Stage 3-4. Но вариант добавил

                                            +1
                                            То что в этой ревизии добавили кажется незначительным.

                                            Ну, про dynamic import такое сложно сказать. Очень мощная и ценная фича, поддержки которой очень давно не хватало ES-модулям.
                                            Другой вопрос, что она относительно неплохо эмулируется через тот же require.js, но хотелось бы верить, что мы в обозримом будущем придём-таки к единой системе модулей.

                                            Но я согласен в плане того, что в остальном изменения довольно минорные, а многих вещей, которых очень не хватает, нет даже на более ранних стадиях.
                                            У меня лично это:
                                            1. менеджеры контекстов;
                                            2. множественные таргетированные catch;
                                            3. генераторы (comprehensions).

                                            Но, видимо, у всех очень разное понимание того, какие фичи в первую очередь «ощутимо упростят разработку». :)

                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                          Самое читаемое