Автор — Lea Verou — одна из самых знаменитых фронтендеров мира, с сотней выступлений на конференциях, одной из лучших книг в мире по CSS и членством в w3c.
старый синтаксис заставляет её быть настолько длинной, что вынуждает разработчика таки разбить её на несколько инструкций. Я бы и с новым за такое по рукам бил, но если не экономить на строчках, то на "совсем старом" синтаксисе получится (не считая особенностей const)
if (obj.optionalMethod && obj.optionalMethod.apply(this, param)) {
var a = x.a
} else if (y !== undefined) {
var a = y.a
} else {
var a = 1
}
Я понимаю, что никто не запрещает писать с новыми фичами не экономя строк
И я твёрдо уверен, что каждая из использованных в примере фичей — крайне полезна, большинство из них я регулярно использую.
Но монстры, которых МОЖНО породить с этими возможностями, пугают :)
Не могу удержаться процитировать прекрасного aemkei и сравнить свою конструкцию с полностью валидным JS:
P.S: как раз на картинке используются только самые базовые функции JS и развлечения с приведением типов
Несмотря на то, что добавление нового функционала не может не радовать, синтаксические извращения, появляющиеся за счёт этого добавления, вызывают расстройство, страшно представлять себе, как разбирать конструкции типа
let {a} = obj.optionalMethod?.(...param) ? x : y ?? #{a: 1}
обучение языку превратится в знаменитую картинку "как нарисовать сову"
Признаюсь честно, мидлы тоже не очень этот вопрос берут в среднем.
Да даже опытные сеньоры не из мира фронтенда, иногда пишущие на JS, немного впадают в ступор от, казалось бы, несложного вопроса
А вот тут уже дело в том, что для 8 старых зионов надо в 8 раз больше места в серверной стойке, в 8 раз больше энергии, в 8 раз больше материнских плат и в 8 раз больше блоков питания. И если для вас заменить один эпик на 8 зионов может быть подходящим вариантом, то для датацентра с ограниченным пространством такой альтернативы нет. Ну и не забывайте, что через 5 лет вы будете говорить «зачем мне новый ***еон на1024 ядер, если я могу за эти деньги купить 8 эпиков по 64, они отлично масштабируются» (хоть я и утрирую немножко)
Чрезвычайно любопытно. В большинстве случаев это конечно станет экономией на спичках, но я определённо учту и в собственном коде и при проведении ревью
Не то чтобы я считал себя хоть мало мальски разбирающимся в звуке человеком, но я в один и тот же усилитель включал колонки Microlab Pro3 и те самые С-30. Там надо ну очень большому медведю на ушах постоять, чтобы человек не почувствовал разницу в пользу первых.
Тем более с сабвуфером — если динамик этого сабвуфера больше чем динамик гробов, то физику обмануть будет сложнее — и тот же бас у "средней современной акустики с сабвуфером" будет значительно лучше
разделение расчёта и форматирования
адекватное название переменных
без откровенных хаков
без лишних тяжелых абстракций, типа класса для интервала из поста или генераторов из соседнего комментария
Is it OK to use arrow functions in render methods?
Generally speaking, yes, it is OK, and it is often the easiest way to pass parameters to callback functions.
If you do have performance issues, by all means, optimize!
Ваше замечание, несмотря на то, что в определенных случаях имеет право на жизнь, в огромном количестве ситуаций неактуально.
Слишком большое количество людей считают этот подход ужаснейшим антипаттерном, коим он не является
Автор сделал грандиозную работу, и классно что выложил в оупенсорс, но должен согласиться с предыдущим комментатором, в react-jsonschema-form именно для построения форм на основе схемы API приятнее и лаконичнее
В своё время я тоже приходил в восторг от огромных корпусов, был у меня и один полноразмерный чифтек.
Сейчас мне настойчиво кажется, что в такую дуру ставить mATX мать, 2 винта и одну видеокарту — это как возить одного человека в туристическом автобусе. Забавно, но нерационально
Половина комментаторов нам тут говорят, что при инициализации методы предка дёргать нельзя, а вы утверждаете, что предок инициализируется полностью именно для того, чтобы дёргать его методы.
Но мой основной вопрос всё равно не про это — почему инстанс класса предка сразу бы не инициализировать со значениями полей, переопределёнными в классе-потомке?
Она и сейчас достаточно быстра. Но с учётом разницы в доли миллисекунд на один промис
, нужно хорошо подумать, отыграет ли разница в производительности библиотек на вашем конкретном приложении время, потраченное на загрузку и инициализацию библиотеки
Если бы дело конструктора было только в инициализации состояния, любые другие действия вообще запрещалось бы делать на уровне языка. Да и понятие инициализации состояния — довольно размытое, конкретно в моём случае, например, метод this.render просто неудачно назван, он не создаёт никаких dom элементов и не изменяет сторонние объекты, он просто компилирует в себя шаблон.
Это вполне подходит под понятие инициализации состояния, как я считаю
А в приведённых выше ссылках например написано, что для языка C# инициализация переменных класса-наследника происходит ДО вызова конструктора родителя, что уже делает наш спор не таким однозначным.
И само наличие десятков (я привёл маленькую выборку) статей на подобные темы значит именно то, что у других наших коллег тоже возникают вопросы по этому поводу, разве нет?
Вопрос по второму пункту. Почему нельзя? Почему мы в этот момент ожидаем, что объект базового класса уже готов? В памяти нигде нет ОТДЕЛЬНОГО объекта базового класса, есть один объект, в который добавляются свойства и методы.
На мой взгляд, это вполне могло быть реализовано внутри как
this.prop = Subclass.prototype.prop || Baseclass.prototype.prop, а потом уже вызов конструктора с проинициализированными полями.
Да, был выбран другой способ, но это не значит что он очевиден
Согласен. Наткнулся я на эту проблему именно в связи с тем, что в Marionette по сути конструктор ты не объявляешь, а исполнялся и перерабатывался в конструктор как раз метод initialize
Вот только про "не используйте глобальные переменные" только что на заборе не пишут, а вот с проблемой излишней логики в конструкторах я, например, столкнулся впервые
Я не вижу причины, кроме выбора авторов языка, почему объявленные поля класса-наследника не могут быть инициализированы до вызова конструктора. Поля родительского класса определяются именно до вызова конструктора, и ожидать такое поведение от класса-наследника мне не кажется какой-то несусветной глупостью
Она не спутала TS и flow :)
старый синтаксис заставляет её быть настолько длинной, что вынуждает разработчика таки разбить её на несколько инструкций. Я бы и с новым за такое по рукам бил, но если не экономить на строчках, то на "совсем старом" синтаксисе получится (не считая особенностей
const
)Я понимаю, что никто не запрещает писать с новыми фичами не экономя строк
И я твёрдо уверен, что каждая из использованных в примере фичей — крайне полезна, большинство из них я регулярно использую.
Но монстры, которых МОЖНО породить с этими возможностями, пугают :)
Не могу удержаться процитировать прекрасного aemkei и сравнить свою конструкцию с полностью валидным JS:
P.S: как раз на картинке используются только самые базовые функции JS и развлечения с приведением типов
Несмотря на то, что добавление нового функционала не может не радовать, синтаксические извращения, появляющиеся за счёт этого добавления, вызывают расстройство, страшно представлять себе, как разбирать конструкции типа
обучение языку превратится в знаменитую картинку "как нарисовать сову"
Признаюсь честно, мидлы тоже не очень этот вопрос берут в среднем.
Да даже опытные сеньоры не из мира фронтенда, иногда пишущие на JS, немного впадают в ступор от, казалось бы, несложного вопроса
Вы же понимаете, что говорите сейчас примерно "Новая порше всего на 50% быстрее моего 10-летнего фольксвагена поло, а стоит в 30 раз дороже"?
Весьма скептично относясь к вопросам, которые указаны в статье, таки не могу удержаться от приведения моего любимого вопроса по JS на собеседованиях
Что вернёт каждый из вызовов?
На удивление, довольно много собеседуемых мной завалились на этом вопросе, что в прочем не оказало решительного влияния на результат собеседования
Чрезвычайно любопытно. В большинстве случаев это конечно станет экономией на спичках, но я определённо учту и в собственном коде и при проведении ревью
Не то чтобы я считал себя хоть мало мальски разбирающимся в звуке человеком, но я в один и тот же усилитель включал колонки Microlab Pro3 и те самые С-30. Там надо ну очень большому медведю на ушах постоять, чтобы человек не почувствовал разницу в пользу первых.
Тем более с сабвуфером — если динамик этого сабвуфера больше чем динамик гробов, то физику обмануть будет сложнее — и тот же бас у "средней современной акустики с сабвуфером" будет значительно лучше
Хотел бы оставить пример, какой код меня удовлетворил бы, доводись мне как лиду задать такую задачу на собеседовании
разделение расчёта и форматирования
адекватное название переменных
без откровенных хаков
без лишних тяжелых абстракций, типа класса для интервала из поста или генераторов из соседнего комментария
Я, пожалуй, приведу цитату с сайта reactjs.org
Ваше замечание, несмотря на то, что в определенных случаях имеет право на жизнь, в огромном количестве ситуаций неактуально.
Слишком большое количество людей считают этот подход ужаснейшим антипаттерном, коим он не является
Автор сделал грандиозную работу, и классно что выложил в оупенсорс, но должен согласиться с предыдущим комментатором, в react-jsonschema-form именно для построения форм на основе схемы API приятнее и лаконичнее
В своё время я тоже приходил в восторг от огромных корпусов, был у меня и один полноразмерный чифтек.
Сейчас мне настойчиво кажется, что в такую дуру ставить mATX мать, 2 винта и одну видеокарту — это как возить одного человека в туристическом автобусе. Забавно, но нерационально
Половина комментаторов нам тут говорят, что при инициализации методы предка дёргать нельзя, а вы утверждаете, что предок инициализируется полностью именно для того, чтобы дёргать его методы.
Но мой основной вопрос всё равно не про это — почему инстанс класса предка сразу бы не инициализировать со значениями полей, переопределёнными в классе-потомке?
Она и сейчас достаточно быстра. Но с учётом разницы в доли миллисекунд на один промис
, нужно хорошо подумать, отыграет ли разница в производительности библиотек на вашем конкретном приложении время, потраченное на загрузку и инициализацию библиотеки
Если бы дело конструктора было только в инициализации состояния, любые другие действия вообще запрещалось бы делать на уровне языка. Да и понятие инициализации состояния — довольно размытое, конкретно в моём случае, например, метод this.render просто неудачно назван, он не создаёт никаких dom элементов и не изменяет сторонние объекты, он просто компилирует в себя шаблон.
Это вполне подходит под понятие инициализации состояния, как я считаю
А в приведённых выше ссылках например написано, что для языка C# инициализация переменных класса-наследника происходит ДО вызова конструктора родителя, что уже делает наш спор не таким однозначным.
И само наличие десятков (я привёл маленькую выборку) статей на подобные темы значит именно то, что у других наших коллег тоже возникают вопросы по этому поводу, разве нет?
https://isocpp.org/wiki/faq/strange-inheritance
https://www.codeproject.com/Tips/641610/Be-Careful-with-Virtual-Method
https://lustforge.com/2014/02/08/dont-call-non-final-methods-from-your-constructor-please/
По итогу написания этой статьи, я смог найти довольно немало статей разного возраста про другие ЯП на английском, в которых описывается эта проблема. Это значит, что кому-то ещё это приходило в голову, а значит не так уж это и очевидно
И да, по приведённой Вами ссылке есть тикет на довольно близкую тему
https://github.com/tc39/proposal-class-fields/issues/151
Вопрос по второму пункту. Почему нельзя? Почему мы в этот момент ожидаем, что объект базового класса уже готов? В памяти нигде нет ОТДЕЛЬНОГО объекта базового класса, есть один объект, в который добавляются свойства и методы.
На мой взгляд, это вполне могло быть реализовано внутри как
this.prop = Subclass.prototype.prop || Baseclass.prototype.prop, а потом уже вызов конструктора с проинициализированными полями.
Да, был выбран другой способ, но это не значит что он очевиден
Согласен. Наткнулся я на эту проблему именно в связи с тем, что в Marionette по сути конструктор ты не объявляешь, а исполнялся и перерабатывался в конструктор как раз метод
initialize
Вот только про "не используйте глобальные переменные" только что на заборе не пишут, а вот с проблемой излишней логики в конструкторах я, например, столкнулся впервые
Я не вижу причины, кроме выбора авторов языка, почему объявленные поля класса-наследника не могут быть инициализированы до вызова конструктора. Поля родительского класса определяются именно до вызова конструктора, и ожидать такое поведение от класса-наследника мне не кажется какой-то несусветной глупостью