Комментарии 137
$static ($debounce ($bindable ($memoize (function () { ... })))),
Убивать вообще никого не надо, агрессия нынче не в моде.
this.x
отличается от prototype.x
и как работают замыкания. И вот ведь незадача! — часто человек весь из себя редукс, а на такие вопросы не отвечает. Мне чтобы для себя ответить на эти вопросы, пришлось много лет делать свой фреймворк. Я об этом не жалею, потому что это позволило мне разобраться в JavaScript вплоть до самых его кишок. Но именно поэтому я не осуждаю людей, которые не знают что такое .prototype
или зачем нужен Object.create
— потому что понимаю, сколько надо потратить личного времени, чтобы в этих деталях разобраться. У большинства людей на работе просто нет задач, которые это требуют.
При этом, при выборе сотрудника на работу я действительно отдам предпочтение тому, кто разбирается в используемых инструментах на самом низком уровне. Возможно, это просто предрассудок и суеверие, не знаю.
Возможно, это просто предрассудок и суеверие
Нет, это принцип «смотреть на пару уровней абстракции вниз», старина Джоэл про него писал в статье «Дырявые абстракции».
Покажете такого человека? А то все ими грозите, а на практике не встречал людей кто не знает про прототипы, но хорошо знает redux
Там ни слова про прототипы, в основном вопросы на внимание к typeof. Ну и, естественно, как там чувак сказал в комментах: "if these scenarios… come up for you in practice quite often, then you are doing it wrong."
(function f(){
function f(){ return 1; }
return f();
function f(){ return 2; }
})();
Тест как раз нормальный, реалистичный. Потому что на большинстве работ вы будете заняты как раз тем, что будете переписывать легаси код, в котором вот такого будет полно. Вы конечно можете всегда найти работу в светлом и чистом стартапе (чтобы потом в будущем кто-нибудь точно так же чесал репу над вашим кодом), но надо понимать реалии рынка — в мире есть очень много плохо написанного кода, который нужно поддерживать или хотя бы переписать. А для этого нужно как минимум уметь в сортах говна разбираться.
Как пел Кровосток, «в наше время, в нашем месте, стоит разбираться в жести...»
var x = 1;
if (function f(){}) {
x += typeof f;
}
x;
Это всего лишь редуцированные до абсурда примеры, поэтому они и кажутся абсурдом. На деле за каждым таким примерчиком стоит какой-то очень сложный и заковыристый баг из реальной практики. Который, если свести его к минимальному примеру, даст вот такой, кажущийся очевидной глупостью, сниппет кода.
- Cannot implicitly convert type 'void' to 'bool', либо Not all code paths return a value
- Operator '+' cannot be applied to operands of type 'int' and 'Type'
- Only assignment, call, increment, decrement, and new object expressions can be used as a statement
Я понимаю, что возможно там удалено много кода, и на самом деле это разбавлено кучей кода, который не оказывает влияния на поведение, но делает ошибку менее заметной, но блин яхз как можно не заметить сразу все вышеперечисленное. И ладно, я допускаю, что такое может случиться в продакшне, но считать это тестом по ЯП это я просто не знаю. Могу предположить, что где-то встречаются индивиды, которые оставили после себя на поддержке подобные перлы, и для отбора кандидатов на саппорт в эти самые места можно было бы использовать такие тесты, но он позиционируется как мейнстрим…
Ребята работающие с БЭМ, будут интересны ваши комментарии по поводу смены места работы, есть ли сложности с этим.
Для больших нужных проектов есть другие технологии. Отличные от JS. Со строгой типизацией и нормальными классами. В которых во главе угла не мода, а читаемость, понятность кода, единообразие стандартных решений. Что позволяет годами поддерживать продукт с >100K LOC, просто и комфортно рефакторя старый код, а не подрываясь на "а давайте перепишем все на этой новой и блестящей свистоперделке".
Все js разработчики всегда плюются в сторону классов и типов, но при этом лучшие из них создают свою собственную систему классов / типов, а V8 под капотом типизирует создаваемые объекты.
Некоторые и вовсе собрались и создали TypeScript. Казалось бы крутая штука! Но как и все, что делается под эгидой Microsoft — сделано криво.
Дошло до того, что в ES2015 все же ввели классы, но не ввели типизацию (надеюсь, еще одумаются), теперь половина плюется, половина с радостью использует. Классы на самом деле хороши, но нету модификаторов доступа (public, private), которая иногда очень даже нужна. Нету полей класса, их можно объявить только через конструктор.
Почему все крутые чуваки в мире JS (ES) всегда стараются изобрести велосипед?
Вот уже много лет есть готовый язык, который основан на базе ES5, в котором есть Классы, Декораторы, Spread syntax, Поля классов, Модификаторы доступа, Интерфейсы. При этом язык позволяет создавать и использовать анонимные объекты и функции как в ES5, позволяет не описывать типы у параметров и возвращаемых значений, позволяет принимать любые значени (т.е. писать в ES5 стиле).
ActionScript3 — язык созданный на базе ES5, для Flash. Но сам синтаксис очень вкусный и без проблем подошел бы как путь развития синтаксиса ES.
Мой посыл был в том, что можно же взять такой синтаксис за основу и просто прикрутить к нему синтаксический сахар в виде стрелочных функций, асинхронных функций и генераторов.
Классы это просто удобная декларативная форма конструирования прототипов, ничего плохого в этой абстракции нет per se. Плоха именно ES6 реализация, которая ломает идею «прототипы это тоже объекты» на уровне синтаксиса. То есть было:
Foo = $class ({ methodA: ..., methodB: ... })
стало:
Foo = class { methodA () { .. } methodB () { ... } }
Это даунгрейд по сравнению с ES5, по той причине, что прототип синтаксически перестал быть объектом, и я не могу переопределить реализацию class
, добавив какой-нибудь препроцессинг этого. Для этого появился костыль в виде декораторов:
Foo = @decorate class { ... }
Но — ха-ха — это все равно даунгрейд, потому что внутри { ... }
у нас не объект. Там другой синтаксис, который является подмножеством JSON — не позволяя делать key: value
, а значит, теряя в выразительности.
Никакого смысла в ключевом слове class
нет — оно не решает ни одну проблему, но создает кучу проблем. Все плюшки классового синтаксиса доступны и в объектах. Вот смотрите:
obj = {
method () { },
get prop () { },
foo: bar
}
Видите? Я могу так же коротко записывать методы и акцессоры, но при этом я не теряю возможности сделать foo: bar
. В ES6 достаточно было сделать лишь это, не было никакой нужды вводит ключевое слово class
.
Проприетарные системы классов в JS просто выглядят так, как будто они пытаются имитировать классы. На деле они дают намного больше чем классы, и по факту являются просто абстракцией, позволяющей удобно описывать прототипы. И эти системы потому у каждого фреймворка свои, потому что у каждого решают какие-то свои задачи, специфичные для фреймворка. Скажем, где-то есть миксины, где-то нет. Ключевое слово class
все ломает, запрещая разработчикам как-то встраиваться в механизм создания прототипа, фиксируя этот механизм, обрубая все замечательные возможности, которые появились в различных фреймворках.
Когда разработчики стандарта JS осознали, что же они натворили — бегом побежали делать декораторы, которые эту проблему немного позволяют решить. Но правильным шагом было бы исключить class
из стандарта (сделать его deprecated), и развивать идею декораторов для объектов. Оставив задачу конструирования прототипов в userland. Потому что там нужна гибкость, и классы в ES6 эту гибкость уничтожили.
Брр, не подмножеством, конечно же, а вообще несовместимой с ним фигней, усложняющей язык.
Класс из ES2015 (принято же так называть, а не ES6) действительно не столь хорош, каким бы мог бы быть. Я выше приводил пример языка, который был бы отличным путем развития.
class Foo {
private var _startPoint: {x: 5, y:10};
private var _callback:Function;
function set startPoint(startPoint) { this._startPoint = startPoint; }
function get startPoint() { return _startPoint; }
function set callback(func:Function) { _callback = func; }
}
Это лишь для демонстрации синтаксиса. Как видно, то, что вам не нравится в ES2015 в том же as3 реализовано так, как вам хотелось бы. Хотите — пишите в ES5, хотите пишите в виде ООП.
Т.к. это все же ES, никто не отменяет использование прототипов, можно уже существующим объектам подсунуть миксин.
Да, я согласен с тем, что классы (как сущность в синтаксисе) нужны для того чтобы статическим анализаторам (системе типов) облегчать работу. То есть в данном случае это просто контракт типа, который говорит что «а вот у нас такие методы есть», и это сразу доступно сразу после разбора AST, без необходимости делать глубокий вывод типов, как это делают инструменты типа Tern. Документацию опять же генерить легче.
Аннотации типов (и их статический анализ) в JS сейчас уже вовсю появляются — в статье про это упомянуто (Flow). Так что это может быть внешним инструментом.
Мне вообще очень нравится на самом деле то как развивается JS. Новые расширения языка сначала появляются извне, как внешние инструменты. А потом уже стандартизуются, когда становится очевидно, что это работает и работает хорошо. Babel это лучшее что случилось с JS за последние годы — а вовсе не «костыль», как многим кажется. Потому что стандарты делаются для людей, а не люди для стандартов. И чтобы понять, что нужно стандартизовать — это сначала должно быть опробовано людьми (комьюнити) и зарекомендовать себя. Но такой фидбек луп был невозможен до Babel.
Потому что там нужна гибкость, и классы в ES6 эту гибкость уничтожили.
Что именно классы уничтожли? Что мешает их не использовать если они вам не подходят?
Не использовать их, к счастью, мне ничто не мешает. Но именно поэтому я и недоумеваю, зачем они вообще нужны. Их функциональность прекрасно была доступна на уровне библиотек, и при этом была намного гибче. Что именно они уничтожили, я описал в начале статьи (где про декораторы написано). Без декораторов для моих задач ES6 классы вообще выглядят как бессмысленный огрызок.
Пока что мне вот подсказали, что для статического анализа типов классы хорошо, как хинт. Это действительно так, наверное.
Пока что мне вот подсказали, что для статического анализа типов классы хорошо, как хинт.
Любому программисту это должно быть очевидно.
и при этом была намного гибче
Вот как раз на «уровне библиотек» и «гибче» не позволяет использовать преимущество классов — жесткая и однозначно интерпритируемая/анализируемая структура.
Не стоит слепо повторять чужие слова, об «уничтожили» и тому подобное.
Какие чужие? Это мои слова, и это основано на моём опыте. Я как раз делал систему классов и декораторов для ES5, и вижу какие напряги возникают с попытками перенести это на нативные ES6 классы. Я не готов отказываться от этого только для статического анализа типов, это совершенно неразумный tradeoff в моем случае.
Просто вы видимо пришли из мира Java и пытаетесь писать код в таком же стиле. Разумеется, в таком случае JavaScript покажется каким-то ущербным Java без системы строгой статической типизации. Но это просто потому что вы не понимаете фишки JS.
Но это просто потому что вы не понимаете фишки JS.
Опять же не стоит бросатья такими громкими словами, а то люди могут подумать что вы не инженер, а хипстер из тех самых кто обычно громче всех кричит.
Согласен, я погорячился с выводами. Просто я часто замечаю, что люди пытаются сделать из JS какой-то Java, хотя куда правильнее было бы двигаться в сторону функциональных вещей — и таким образом достигать статической верифицируемости. Собственно, я в этой статье и изложил видение того, как этого можно было бы достичь. А прототипы и динамичность языка мне нравятся именно возможностями метапрограммирования (embedded DSL), и это не очень пока совместимо с Java-подходом. Java это такой энтерпрайз-фашизм, а в JS есть дух хардкора, молодости и эксперимента. И вот это я и называю «фишкой».
Это было очень сильное заявление. Оно очень точно описывает все программные продукты от IBM.
В java «хардкора» не меньше, чем в js, он просто другой =)
но обсуждение этого топика скатится в холивар)))
Как я писал ниже, есть настроения писать серьезные приложения на js с большими объемами логики (фактически заменить нативные приложения). Эти приложения должны быть Легкими в поддержке и Быстрыми в изучении.
Вот к примеру какая-нибудь программа для расчета бухгалтерии. Сейчас есть онлайн-решения, но они построены по принципу тонкого клиента. А ведь можно же сделать толстый клиент, который сможет работать оффлайн и не будет на каждый чих дергать бекэнд.
Объемы бизнес логики в бухгалтерском приложении неимоверные. А при текущем положении дел такое приложение будет состоять из сырых хеш таблиц и функций, которые с ними работают.
Но в целом да, можно сказать: «не хочу в такой проект, я хочу что-то классное!»
Просто вы видимо пришли из мира Java и пытаетесь писать код в таком же стиле. Разумеется, в таком случае JavaScript покажется каким-то ущербным Java без системы строгой статической типизации. Но это просто потому что вы не понимаете фишки JS.
Я уже почти десять лет как JS-программист, и пришел в него далеко не из джавы. Я писал правда большие вещи, библиотеки, игры, которые активно развивались и успешно поддерживались годами. Это не каждые полгода новый сайтик на 50 табличек сверстать. Статическая типизация — это не wish, это необходимость для любого крупного проекта, который не должен быть заброшен через месяц после релиза и у которого стоят высокие требования к качеству. Мы к этому пришли не с «Джавы», а кровью, разгребая динамическую типизацию. Хотя еще пять лет назад я был уверен, что утиной типизации — хватает:
Типизация — утиная, JavaScript не содержит подводных камней, просто люди не могут его понять
Декораторы — и вполовину не дают всего необходимого. Именно потому у них там от силы memoize, debounce и т.п. заваливается. Тот же memoize вообще бесконтрольный — плюет в память неограниченно и навсегда, да и невозможно вменяемо почистить от устаревших данных. Как покрыть тестами функцию, на которую наложили debounce?
Я уж молчу об оптимизации. Я понимаю, что современным хипстерам срать на нее хотелось и они готовы использовать
O(n2)
вместо O(n)
исключительно для понтов, чтобы функцию можно было назвать чистой, пол-стейта приложения пересоздается ради того чтобы изменить три поля, МусороСборщик не хипстер, все сдержит, а функция заворачивается в функцию в функции, которую вызывает функция через функцию, в результате стек-трейс не влезает в экран. Но лично мы по-максимуму отказались от замыканий (постарались вынести их в момент инициализации игры или заменить на циклы, а эвенты — это методы обьектов) и этим +30% производительности игре добавили. А это, кстати, 60 фпс вместо 45. А это еще мы не использовали всякие новомодные «давайте 100 раз пересоздадим объект для того, чтобы сделать элементарную операцию». А операция такая. У вас 10000 объектов, которые приходят с сервера. У них есть свойство, например Группа. Необходимо сгруппировать их по этому свойству в массивы. Вот процедурный код:
(objects) {
let result = {};
for (let obj of objects) {
if (result[obj.group] == null) {
result[obj.group] = [ obj ];
} else {
result[obj.group].push( obj );
}
}
return result;
}
Как написать новомодно?
(objects) {
return objects.reduce((result, obj) => ({
...result,
[obj.group]: [
...(result[obj.group] || []),
obj
]
}), {});
}
Черт ногу сломит, линейное количество выделений памяти, квадратичное количество операций, зато модно, иммутабельно и можно перед другими хипстерами похвастаться, какой у тебя поддерживаемый код.
Я тоже делал систему классов в далеком 2010-м. И я ее делал по той простой причине, что не существовало такой системы, которая поддерживала б современные на тот момент технологии, например аксессоры(get, set). Да, современные классы далеко не идеальны. Они очень далеки от идеала. Как и деструктуризация, которая имеет другой синтаксис в сравнении с импортом. Но ключевое слово «класс» нужно. Чтобы движки нормально оптимизировали инстанциирование, без костылей с иннер-классами, чтобы проверять ошибки на этапе компиляции (а для этого еще нужна типизация, пусть и опциональная), чтобы иметь нормальное автодополнение в IDE, когда оно не вываливает мне на голову тонну всего, что похоже и чтобы IDE подсвечивала, когда я ошибаюсь. Чтобы было нормальное логирование в консоли, где я видел бы, что именно представляет из себя этот объект. Чтобы, когда я открываю чужой код, который писали 6 месяцев назад и вижу там аргумент
config
мне не приходилось использовать телепатию, звать того человека или ставить логирование, запускать код, смотреть что пришло, а потом на продакшене выяснить, что оно еще, в другом месте может получить совершенно другие данные, которые проходят утиную типизацию в старой логике, но не проходят в новой. Я уж молчу, что классы тестами покрываются очень легко — есть методы, есть состояния, которые можно проверить. Когда ж человек, который думает, что он пишет на ФП начинает комбинировать функции и использовать функции, которые возвращают функции — это покрывать тестами черт ногу сломит. Самый простой пример — React.PropTypes.shape возвращает функцию, которая не валидирует вне своего контекста. Замыкания по сути выполняют роль классов, только ты в классах явно описываешь стейт, а замыкание — какой стейт захочешь — такой и захватишь, при этом он не логируется в консоли, плохо чистится сборщиком мусора и совершенно неявный.проверять контракты типов для свойств в JavaScript — так что наш ToggleButton мог бы выглядеть так:
ToggleButton = ({ label : String, toggled = false }) => <button toggled="{toggled}">{label}</button>
И при этом обязательность и тип свойства label проверялись бы еще до запуска программы!
Нет, не получится, в деструктуризации нельзя указывать типы. Тут обсуждаем варианты:
https://github.com/facebook/flow/issues/235
В свете этого, «классовая» запись выглядит просто как кривой бессмысленный костыль — и оно бы таким и было, если бы не один важный момент
Вот только имея на руках повторяемую структуру — каждый раз описывать в деструктуироемом аргументе ее — та еще боль. Я уж молчу, что там обычно описываются не все свойства, которые приходят и чтобы добавить фичу — приходится заморачиваться с тем, чтобы понять, что в этом месте вообще может быть.
И да, механика классов в ЖС пока малоюзабельна из-за ряда проблем, но это не причина отказываться от них и их развития в будущем, как говорит один из тех хипстеров по ссылкам, которые дал автор.
Про то что Flow не умеет в типизацию destructuring-выражений это, конечно, печально — но думаю это всего лишь временная неувязка. По поводу ваших сетований об алгоритмической сложности «хипстерского» (wtf) кода — вы же должны понимать, что это лишь специфика вашей работы (игры?), связанной с повышенными требованиями к производительности.
В достаточно сложном проекте (ERP предприятия), работающем с кучей данных (сотни тысяч записей в таблицах, обрабатываемых на client-side) мне пришлось всего пару раз вручную написать цикл — это собственно, табличный контрол который осуществлял виртуализацию рендеринга и фильтрацию/сортировку датасетов. Во всем остальном, «прикладом» коде я с радостью использовал все прелести функциональных выражений, вообще не думая о том, насколько быстро они работают (покуда это не начинало тормозить).
Premature optimization is the root of all evil, как говорится. Я в JS пришел из C++ и дико рад, что мне в моих повседневных задачах больше не надо думать о таких вещах, как ручной менеджмент памяти или там, упаси боже, какие-нибудь cache misses. Я хочу забыть про это, как про страшный сон, и заниматься вещами поинтереснее, чем бессонными ночами думать о «протекающих абстракциях» в моем коде. Покуда он работает и работает приемлемо — я не хочу об этом думать.
Статическая типизация — это не wish, это необходимость для любого крупного проекта, который не должен быть заброшен через месяц после релиза и у которого стоят высокие требования к качеству.
Вот я тоже удивляюсь как люди этого не могут понять, просто молятся на свое ФП. Видимо не сталкивались с большимим проектами и с тем когда разработчики в команде разного уровня. ФП (а также миксины и прочее функциональное месиво) хорошо в блоге показать, на ютюбе роликов сделать, но не для разработки больших и серьезных проектов.
Но! Почему-то миллионы леменгов хотят принести ООП и систему классов. Стоит посмотреть на старые библиотеки / фреймворки. Каждая из них вводит свой вариант создания Класса. jQuery, Backbone, Lodash, у них у всех свой путь к созданию эдакой системы типов. «Более современные» идут тем же путем.
Ответственные за развитие ES вводят классы. Может не все так хорошо с этим путем?
И ведь это все мы сейчас смотрим только с точки зрения веба (js для работы с DOM), тут и вправду можно обойтись ES5 и компонентным подходом к написанию кода.
Но кроме как для работы с DOM js используется еще и на бекенде (node.js | express.js). На js сейчас пишутся огромные веб-приложения с кучей бизнес логики (не только манипуляция с DOM). А еще игры пишут на js.
И вот для больших приложений и игр без объектной модели довольно тяжело будет обеспечивать поддержку.
Вот представим, что у нас есть Quake, написанный на js (Quake — это очень маленькое, по объемам логики, приложение). И у нас есть ошибка, конкретную точку, где она проявляется — мы знаем. Как найти все пути, которые приводят к этой точке кода?
> Да, это целая проблема. Потому что: https://www.youtube.com/watch?v=wfMtDGfHWpA
Система классов не подразумевает под собою наследование. Более того, с наследование — это действительно боль (в большинстве случаев). Классы очень хорошо можно использовать для типизации (классификации), к примеру, чтобы не в комментах писать, какой тип может приниматься методом, а напрямую в декларации метода его вставить. Так же, система классов позволила бы улучшить производительность рантайма: точно известно сколько памяти нужно выделить, точно известно, сколько полей есть в классе, известны ссылки на методы и т.д.
ps: у этого парня в примере есть грубая ошибка: он использует один state для разного поведения, и если несколько поведений будут использовать одну и ту же проперти в state — будет очень больно.
т.е. код красивый, но при первом же конфликте пропертей все будет работать очень странно.
Сразу оговорюсь, мне больше нравится немного улучшенный Си-шный вариант ООП: структуры с методами, которые имплементят интерфейсы.
Интерфейсы описывают Тип, «структуры с методами» (так и тянет сказать Класс) — имплементация Типа. Желательно без наследования.
Все взаимодействие ведется либо через Тип, либо через Конкретные «структуры с методами» (когда разные имплементации не подразумеваются).
— это я подразумеваю под определением Класса.
Но и наследование иногда полезно иметь, прототипное наследование всем нравится, а оно имеет ту же суть.
> Поскольку весь код написан на pure functions, никаких посторонних эффектов быть не должно.
1. FP, Immutable data
Не столь принципиально, каким путем пойти, FP и OOP справятся в целом одинаково.
Но вот Immutable data… Immutable data для шутера! В этом случае GC будет вызываться очень часто, ваш ноутбук будет перегреваться, FPS будет… FPS иногда будет =)
2. pure function, global state
если все будет на pure function, то кто будет обновлять состояние?))
Если нужно выполнить 10 изменений, можно из объекта сделать билдер, на нем произвести эти 10 изменений, и наружу отдать новый экземпляр неизменяемого объекта. Тем самым вместо 10 клонирований будет всего 2.
но это отступничество от идеологии, как и global state =)
Возможно FP может помочь? Например Redux с глобальным state и Immutable data может помочь отследить что привело к этой ошибке. Плюс в реальном времени её можно пофиксить. Поскольку весь код написан на pure functions, никаких посторонних эффектов быть не должно.
Вы пробовали дебажить Редакс? Крупные игры — это не веб-сайты, где много одинаковых табличек, тут кустарные вещи работать не будут.
Flowtype для слабаков, да? ;)
Вот прям из всех щелей прет типизация, но ее не пускают и даже не хотят рассматривать. А прет на сколько сильно, что даже пишут свои велосипеды (хинты через jsdoc) и расширения для стандарта как плагины для babel.
Мое сообщеним именно про это и было, что развитие похоже на изобретение нового лучшего велосипеда. И потом годами идет разнобой в спецификации и в реализации. По спеке уже давно есть классы, генераторы и т.д., на деле — только babel спасает, нужно все в ES5 транслировать.
Можно конечно сказать «Да кому нужны пользователи IE!!! Пусть ставят FF или Chrome!», но как ни крути, не везде такой ответ будет адекватным. Да ни FF, ни Chrome не поддерживают еще полноценно ES2015, а уже почти 1 год прошел :)
Я не столь часто использовал TypeScript, так что могу ошибаться с выводами, но на моём опыте, используя его — там сделаешь поблажку, тут, у тебя всё в конце концов, грубо говоря, превратится в один большой any
, хотя казалось бы, всё так хорошо начиналось. И требования к декларации d.ts всё только усугубляют, хотя куча сторонних уже готовых деклараций спасают положение, но всё же...
Мне нравится Flow именно потому, что типизация опциональна и нужна "только там, где нужна". На всё "фигак-фигак" можно смело забивать болт и писать на чистом ES5, а любой критичный код можно собирать даже с рантайм проверками (по крайней мере в dev'е). Единственное чего не хватает — это, например экспортирования указанных типов в Metadata, например для последующего анализа внутри DI контейнера для двойной диспатчеризации. А так — идеал, никому не мешает — хочешь используй, хочешь — нет.
Ну это моё имхо.
Полностью согласен, но это всё издержки подхода "без строгой типизации везде и всюду — жизнь не мила".
P.S. При таких запросах… Ну так Haxe же: https://haxe.org/ =)
Ну это надо либо самому прочувствовать, либо почитать о d.ts хотя бы: https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html (TL;DR: Костыль, ради идеологии)
Вопрос стоял очень просто, добавить немного статического анализа хотя бы на уровне своего приложения. Причем без overhead в виде килобайтов и длительной загрузки собственной системы типов на клиентской стороне.
Никто не рвется переписывать тысячи JS-библиотек, так как типизации нет на уровне виртуальной машины в браузере, и ни один из существующих компиляторов не способен выдать из другого языка высокоэффективный JS-код.
А работать надо здесь и сейчас. И использовать чужие библиотеки, написанные не на typescript, зато оттестированные и проверенные тысячами разработчиков. Отсюда необходимость в d.ts, ну либо как во flow, каждый сам проверяет интерфейсы чужих библиотек.
Резюмируя, TypeScript никогда не позиционировался, как «убийца JS», мало того, не зная JS, писать на нем — самоубийство. Это «синтаксический сахар для JavaScript» https://msdn.microsoft.com/ru-ru/magazine/dn890374.aspx.
И это эффективный помощник для тех, кто понимает.
так как типизации нет на уровне виртуальной машины в браузере
не способен выдать из другого языка высокоэффективный JS-код
На самом деле есть: https://en.wikipedia.org/wiki/Asm.js. То есть типизация на уровне VM вполне себе есть, просто она неявная. Можно писать такой код, который будет в очень эффективные конструкции JIT'ом скомпилирован. Вот из вики пример:
int f(int i) {
return i + 1;
}
function f(i) {
i = i|0;
return (i + 1)|0;
}
Вот эти |0
гарантируют компилятору, что результатом выражения будет тип integer
, и что это можно в эффективные инструкции скомпилировать. Ну это самый примитивный пример. Компилятор Emscripten автоматически все это генерит (это транспилятор из LLVM байткода в JS)
На деле JIT очень продвинутые оптимизации делает, например может понять где у вас POD-структура, а где динамический словарь.
(соответственно, если бы у нас в языке были явные хинты типов, то это существенно облегчило бы работу JIT'у; но суть в том что «под капотом» JS все очень даже типизировано уже — осталось лишь во «фронт-енде» — в самом языке — хинтинг типов добавить — и можно неиллюзорный профит ловить, от возросшей производительности)
На счет Object.setPrototypeOf, не совсем понятно, каким образом прототипное наследование «извне» будет лучше классического (или того же прототипного, но с классическим привкусом, как в ES2015) наследования «изнутри».
Динамически собирать иерархию объектов, с возможностью «множественного наследования», когда порядок подключения родителей имеет значение и порою бывает критическим. Думаю, это не лучший способ построения кодовой базы. Пока это небольшой проект — все будет довольно не плохо, а когда в системе будет несколько сотен сущностей — тут уже будет тяжело поддерживать и разбираться.
Возможно, я не прав или не понимаю этой концепции, но на данный момент у меня такая точка зрения.
class User {
get hi(){
return 'hi'
}
}
let Vova = new User();
console.log (Viva.hi)
Мне этого в моей реализации было достаточно.
Тоже изучал тему статических
свойств классов, на 2ality есть ссылка, что это антипатерн.
Еще есть бабелевская обертка для использования статических свойств.
Хотелось бы разобраться. Если вас не затруднит.
Попробуйте порефакторить эту «функциональную кашу», сразу разберетесь. Функциональщина делает из кода месиво, которое не может быть однозначно интерпретировано на этапе разработке. Происходит разработка скриптов.
https://jsfiddle.net/duskpoet/69z2wepo/53398/
Мб туда надо PureRenderMixin вкорячить?
https://facebook.github.io/react/docs/pure-render-mixin.html
Просто, как я понимаю, по дефолту Реакт свои компоненты не считает за чистые функции. И вызывает render() всегда. Я именно поэтому и упомянул два раза в статье, что описываю «идеализированный» Реакт :)
Кстати — в React 15.3.0 добавили класс верхнего уровня React.PureComponent. Чтобы нормальные пацаны от него наследовались, а не от React.Component. Там render вызывается только, когда нужно
С добрым утром, декораторы депрекейтнули и уже года полтора думают что с ними делать. Т.е. по факту в языке и компиляторе (babel 6) их нет, только в виде leagcy пакета. =)
Ну это меня не печалит, потому что у меня свои «декораторы», которые вообще даже в ES5 работают. Я просто прикидывал, как их можно было бы реализовать, будь у нас нативный синтаксис. Хотя по мне, лучше бы они классы депрекейтнули, ха-ха.
Офигеть, ещё даже не зарелизили, а уже депрекейтнули… Куда катится этот язык?
Это просто SerafimArts панику наводит. На самом деле это не депрекейт, а просто обновляют черновик стандарта, и пока апдейт идет, из Babel временно убрали текущую реализацию (она доступна в виде внешнего плагина). Это нормальный процесс работы, и декораторы еще вернутся. Их уже юзают многие технологии популярные — например ангуляр2, mobx.
Та часть что про keyed lists в диффе.
Будем честны. Все поднятые Вами проблемы решаются сменой языка программирования на тот, в котором statless и promises реализованы на уровне языка. Elm, Clj, F# и ни разу не на TypeScript или "статический" js + Flow. Например
эти чуваки пытаются достичь того же, чего и я — избавиться от классов, перейдя на чистые функции.
Но изначально React создавался, как урезанный Elm с классами. Ну и тэ пэ
Я кстати уверен что в будущем люди не то что «забудут этот недохаскель». Но реально перейдут на хаскель. Ну точнее его браузерную инкарнацию какую-нибудь, типа Elm. Очевидно же, что все к тому идет, просто не революционным, а эволюционным путем. JS все больше и больше становится похож на это, в какой-то момент уже просто не будет смысла использовать JS, все свитчнутся на какой-нибудь транспилируемый в него язык. Они и сейчас есть, такие языки, просто люди еще не понимают до конца, зачем они нужны — но это в какой-то момент станет очевидно всем. И появление таких вещей как React/Redux в массовом сознании это очень мощные сигналы к этому.
[...]
И тут интересный дальше момент — это определяет архитектуру нашего приложения. То есть, выгодно юзать Redux. А это уже все прямиком пришло их функциональных языков, из Elm в частности. И постепенно никакого смысла в том чтобы использовать JS вместо Elm не будет. Потому что Elm позволяет еще и статически верифицировать всю программу так, что у вас вообще нет runtime exceptions. А это и есть ультимативная цель всего этого замеса.
Я хаскеллом не обмазываюсь уже лет восемь, поэтому совершенно выпал из контекста — про ghcjs и purescript впервые слышу. Я про Elm-то узнал буквально на днях, когда узнавал откуда у React/Redux ноги растут. Даже не успел его попробовать толком.
упрощенный Haskell ориентированный на фронтенд
Не упрощённый Haskell общего назначения избыточен и слишком сложен для решения проблем, типичных для клиентской вебморды.
запутанный ffi (вызов js из elm)
Иначе Elm не даст гарантий безопасности рантайма, очевидно же.
Пробую писать на Elm. FFI как такового там нет. Есть так называемые port для взаимодействия с кодом на JavaScript. И есть native-модули, которые естественно пишутся на JavaScript. Непосредственного вызова JavaScript из Elm нет.
Любители Haskell могут также посмотреть на Fay. В отличие от Elm это упрощённый Haskell (нет классов типов) с тривиальным FFI.
Вряд ли Haskell такой уж идеальный ЯП что вот так прям взлетит в будущем, учитывая его сложность. Упомянутый Elm скорее взлетит, ибо он проще. Я собственно про то, что его можно же уже сейчас брать. То есть те причины, по которым его люди избегают ("у меня в проекте DataTimePicker из jQuery UI, как мне его вставить в Elm ?!") мне не кажутся убедительными, если только нет действительно большого количества legacy кода.
Redux наверное хорошо для js-проектов, но по факту он лишь увеличивает вероятность глюков в рантайме — добавляет баги, связанные со стыковкой функций и структур данных приложения с Redux.
Другое дело, что многие web-задачи стали именно такими, требующими скорость исполнения, максимальное покрытие тестами (требованиями) и т.д. И в JS просто нет многих вещей для этого. Но, ИМХО, и не нужно. Ведь задачи, для которых он был создан никуда не делись.
Ну ок, неудобно на нем писать сами компоненты, зато теперь есть пока еще не такая крупная и сложная задача — компоновка этих компонентов, сборка и доставка (webpack.config.js, gulp и т.д.). Станет эта задача большой и сложной, напишем под нее компилятор haskell.
Зато появится задача управления docker-контейнерами, когда нам станет не хватать docker-compose.yml с его возможностями.
Эта цикличность никуда не денется: начинается все с конфигов, потом сложных конфигов с переменными, потом простых скриптов, потом сложных скриптов, а потом уже (через N шагов) вся мощь haskell :-) Я кстати вот не уверен, что пора уже прям до haskell доводить, может хватит пока Java, C# уровня? Так рассудили и создатели TypeScript.
Посмотрите на стили, та же история, CSS, SCSS и сейчас уже в react вот и стили программируемые (react material ui), а в react native и вовсе один способ.
В общем, не нужно трогать JS, нужно перетерпеть ситуацию с компилированием в него и дождаться webassembly.
Есть еще такой момент для размышлений. Что, если нам вообще не нужна надежность и гарантия в браузере? Что если пользователь является частью экосистемы и сам допиливает то, что ему нужно (привет, adblock, userscript и др расширения). Можно конечно давать менять какие-то жестко зашитые вещи (ну вроде как поддержка плагинов), но что если гибкость до самого корня (DOM, сеть и т.д.) является залогом успеха развития веб? Для чего мне жестко зашивать и проверять кучу параметров, а потом выслушивать, что исчез логотип хабра, если каждый пользователь все равно создаст собственный хабр в браузере для просмотра статей. Может стоит не бороться с этим, а возглавить?
А приложения, требующие высокой стабильности и надежности, всегда можно реализовать для каждой платформы нативно.
зато теперь есть пока еще не такая крупная и сложная задача — компоновка этих компонентов, сборка и доставка (webpack.config.js, gulp и т.д.)В нормальных платформах/языках это делает компилятор/линковщик. В js это, как и всё остальное, реализовано через одно место — с помощью гимнастики на волшебных костылях.
Что, если нам вообще не нужна надежность и гарантия в браузере?
Простите, но это похоже на бессвязный поток понятий
Там хватило бы и jQuery.
Код должен быть понятен большинству, а не только крутым перцам.
Такой код дороже.
А еще фейсбук память жрет.
На самом деле, код на jQuery намного дороже. Это примерно как лечить зубы у плохого стоматолога. Вроде бы дешевле, но выходит что дороже. И потерянное время вам никто не вернет.
И оправдано это именно в мегапроектах типа Фейсбука. У них тысячи компонентов, миллионы строк кода. Для маленьких же сайтов-визиток, конечно же, лучше использовать jQuery. Или вообще голый DOM (в jQuery смысла не очень много с появлением нативных селекторов).
Но вот как раз фейсбук не такой сайт.
Вот почему у них миллионы строк кода?
Потому что, грубо говоря, не используют jQuery, а городят огороды.
https://habrahabr.ru/post/308148/
Вряд ли стоит писать на голом js.
Вы уже много фейсбуков написали? :) Просто у вас о нем очень примитивизированное представление. Любой веб-проект на деле намного сложнее чем кажется.
Фейсбук стали использовать React не так давно, значительная часть их кода всё еще на условных «джиквери» (разных предшествующих реакту технологиях, в общем). Если бы они с самого начала юзали React, им бы возможно удалось избежать как раз-таки их этой многомиллионной кодовой базы.
Не спорю.
С морды всей кухни не увидеть.
Но js это более морда и не понимаю, чего там у ФБ такого сложного.
ЛС
Подгрузка ленты
Комменты
Там больше сложностей на бекэнде, а не на фронте.
Это так сложно разбить код хотя бы на файлики?
>jQuery структуру не предоставляет
А плагины?
>и большая часть любителей jQuery не способна самостоятельно задать гибкую структуру.
То есть Вы не используете jQuery из-за того, что кто-то не может задать гибкую структуру? :)
Нет.
Сам использую их только для повторного использования.
Но ничто не мешает.
>В том и дело, что «большая часть любителей jQuery» этим даже не заморачивается.
Ну да, это большинству просто не нужно. :) Вы тоже не используете jQuery из-за того, что кто-то что-то не умеет? :)
>А если в проекте собрались «крутые перцы», которые могут написать «по уму», то почему бы им не взять более удобную технологию?
Выходит менее понятно :)
Куча дырявых абстракций.
https://habrahabr.ru/post/308154/#comment_9763712
Удобную, но более сложную, технологию стоит использовать, когда это оправдано.
Для сайта вроде ФБ и проще вряд ли это оправдано.
Кому-то нравиться прыгать с технологии на технологию, а кто-то решает задачи.
JavaScript: где мы сейчас и куда двигаться