Pull to refresh

Comments 61

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


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

Старый добрый require не является частью EcmaScript.


Рекомендую статью 2013 года — Путь JavaScript модуля.


А инжекции нас и так ждут. Не повод это, от динамических импортов отказываться. Как собственно и от пакетных менеджеров:
Рассказ о том, как я майню эфир через meltdown на ваших телефонах при помощи npm
Охота на вредоносные npm-пакеты
Вредоносный код в npm-пакетах и борьба с ним
Рассказ о том, как я ворую номера кредиток и пароли у посетителей ваших сайтов

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

у нас есть TypeScript

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Синтаксис не сложный (тот же "_" использовать привычно), а семантика всем знакома. Просто теперь это правило еще будет контролироваться рантаймом.
Что мешает сделать приватные переменные таким же примитивным сахаром над замыканиями?)
То, что они им не являются. Невозможно рассматривать # как синтаксический сахар над любыми имеющимися паттернам (будь то замыкания, 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();

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

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

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

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


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

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

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

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

new Foo().destructureX();  // => 1

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


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


Consider protected, abstract, and friend #25


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

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


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

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


Ja Va Script

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


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




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

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

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

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

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

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

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

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

Соглашусь с вами, что под грузом обратной совместимости и тяжелой наркомании разработчиков языка данный модификатор требует некоторого внимания. Приватные члены — это не сложная концепция и выглядит даже логично, если выделять «решетку» именно как модификатор, а не часть имени члена.
Я бы хотел, чтобы для 'use strict2' здесь вылетала ошибка.
То есть ошибка должна вылетать для любого target[prop] = value;?
Спасибо за комментарий. Для меня было не очевидно, что приватные свойства нужно объявлять заранее.
Не за что, для меня тоже это было абсолютно не очевидно. :)
Но надо отдать должно разработчикам V8 за понятные ошибки.
class Foo {
    constructor(x) { this.#x = x; }
}

// Uncaught SyntaxError: Undefined private field #x: must be declared in an enclosing class
КМК приватные штучечки не про нас. Пусть ими пользуются большие команды из сотен человек. Если лично нам они не нужны, это не повод тормозить остальных.

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

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

TS — язык строго типизированный. Это ни хорошо, ни плохо. Это другой способ мышления. Так же как ООП не хуже функционального подхода, они просто разные.
КМК приватные штучечки не про нас. Пусть ими пользуются большие команды из сотен человек.
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 является скорее преимуществом.
По задумке автора кода тайное должно быть скрыто и недоступно для модификации (SOLID — the Open-Closed Principle)
Ну ладно, приписывать модификатор private к инкапсуляции — это распространенное заблуждение. Но вот к принципу открытости-закрытости — вы пробили новое дно. Он совершенно о другом.
Для рефлекшна это должно быть доступно (не проверял, но надеюсь, ибо так работает во многих других языках), но программист должен чувствовать себя грязным после этого действа (=

Вот только доступные для рефлексии приватные поля (так называемые soft private) были в языке давным давно и делались через символы. А в стандарт усиленно пропихивают hard private, ключевым отличием которого от символов является недоступность для рефлексии.

.flatMap() не эквивалентен последовательному вызову .flat().map()

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

Нет. Именно не эквивалентен. Последовательный вызов .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"]
Столько суматохи вокруг приватных свойств, а можно же было простые фабрики с замыканиями использовать
Ещё приватные свойства можно реализовать через прокси-объекты или через символьные ссылки.
Цель предложения — стандартизировать синтаксис и заодно префикс.
Еще викмапы*

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

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

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

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

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

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

Articles