Comments 42
prototype
, напримерprototype
довольно удобно до сих пор использовать в фабриках классов и миксинах.
Когда перенаследоваться по какой-то причине нельзя, а логику общую нужно вынести, можно «обогатить» прототипы родственных классов общими методами, или строить конструкторы на лету все еще бывает полезно.
function ShapeAttrHooks(){}
Shape.prototype.attrHooks = ShapeAttrHooks.prototype = {};
Rect.prototype.attrHooks = new ShapeAttrHooks();
Circle.prototype.attrHooks = new ShapeAttrHooks();
А дальше можно так:
Shape.prototype.attrHooks.foo = 3333;
// магия!
new Rect().attrHooks.foo; // 3333
Очень похоже на статью о Java.)
Меня в JS привлекает как раз его простота и возможность не писать лишнего.
Тем более что язык активно развивается, закрываются детские проблемы — отсутствие модульности или блочные переменные и т.п.
ООП мягко говоря спорная концепция. Где то она применима, например компоненты в React адекватно используют эту концепцию. Но в прикладном коде я не вижу смысла писать классы в 99% случаев, есть отдельно данные и функции которые их обрабатывают но не все вместе.
Компоненты в Реакте давным-давно используют хуки, а не классы. Переход с классов на хуки — это по магнитуде как был много лет назад переход с голого JS на jQuery.
Но функции-прототипы тоже давно в прошлом, конечно. Тем более с typescript и его возможностью делать вещи типа:
class Cls { constructor(public readonly x, public readonly y) {} }
Хуки действительно классная концепция.
Я пока мало занимался разработкой с использованием react и не знал о них.
Уже переписал все на хуки. Кода меньше и код проще.
Где в js уже сейчас можно в параметрах конструктора сразу определить поле класса?
Почему-то многие (почти все, кого я знаю) считают, что JS и TS — почти одно и то же. Питонистам же не предлагают вдруг пересесть на C# или Java! :)
Практика показывает, что нет. Когда пишешь на TS, нужно учитывать то, как это будет выполняться на JS, потому что (внезапно) весь TS пропадает в рантайме.
TypeScript — это скорее надстройка над JS, чем отдельный язык. Можно использовать в одном проекте одновременно JS и TS файлы, и они будут уживаться друг с другом. Так можно постепенно переводить проект в JS на TS.
TL;DR: Надо все-таки думать головой, тесты это дорого, тесты могут цементировать архитектуру, покрытие тестами может быть «попугаями»
На «Пользуйтесь TypeScript» могу ответить «Не пользуйтесь TypeScript» :)
По моему опыту, при программировании чего-то сложнее сортировки очень большое время начинает отводиться на удовлетворение тайпскрипта, а не бизнеса.
очень большое время начинает отводиться на удовлетворение тайпскрипта, а не бизнеса.
Это с лихвой окупается за месяцы и годы поддержки и развития. Может быть для MVP он кому-то и кажется лишним, но для больших проектов с длинным циклом — must have.
Да и если освоится, и в проекте типы и так есть, то на них не так уж много времени тратиться.
В текущем проекте я покрыл (пока что) тестами весь слой работы с данными, при рефакторинге и расширении функционала, не так давно, они мне помогли сэкономить кучу рабочего времени и указали на места в коде, в которых буду возникать баги.
Про UI-тесты я даже писать не стану.
А ещё больше времени отнимает дебаг ошибок, вызванных опечаткой в названии атрибута глубоко вложенного объекта или передачей числа функции, которая ожидает строку.
Как-как вы проверяете внутри функции входящие параметры? Вот предположим, что у меня функция ожидает в первом параметре объект rectangle, состоящий из точки левого верхнего угла и двух длин сторон:
{ upperLeft: {x:23, y:0}, height: 24, width: 60 }
}
А как это делается в TS? Там какой-то хитрый ходи для этого есть или просто сахар который в js развернется точно в такую же проверку?
Ну я вам так скажу, сейчас в js это делается никак. Вот прямо все берут и никак это не делают, потому что проверять надо будет очень многое: что весь rectangle не null, что у reactangle есть такие-то и такие-то свойства и эти свойства имеют ожидаемые нами типы, что у объекта отсутствуют другие свойства, и прочее. Кстати, это не сильно улучшит читабельности вашего кода — пользователь функции должен будет довольно долго соображать, какой же структуры передать объект внутрь нее — будет вчитываться в ваши ифы вместо того, чтобы мельком взглянуть на указанный тип. TS для рантайма тоже не генерирует никаких проектов потому что это же будет ужас, а не код. Зато TS на этапе компиляции позволяет задать тип Reactangle и в процессе компиляции проверить, не передаёте ли вы в вашу функцию какую-нибудь фигню вместо него.
Нет, в сгенерированном коде не будет никаких проверок.
И вот еще о чем я последнее время думаю:
В детстве мы мечтали как в будущем производительность компьютеров вырастит настолько, что мы сможем писать на языках высокого уровня почти всё. Мы наконец забудем компиляторы как страшный сон, ведь человеческое время будет дороже машинного.
Мы будем писать преимущественно на Java, JavaScript, Tcl и тому подобных языках, которые будут выполнятся сразу, без необходимости предварительной сборки или компиляции.
2020 год, и теперь у нас есть Babel, Webpack и TypeScript, для того чтобы «компилировать» наши программы в интерпретируемый (!) JS.
Как так получилось? Почему силы сообщества брошены не на то, чтобы реализовать поддержку всех этих возможностей в интерпретаторе, а на то чтобы создать прослойку сборки между редактором и интерпретатором? Что пошло не так? Где мы ошиблись?
Да, таким образом тс спасёт вас в случае, если вы опечатались в имени свойства объекта, который сами же создали. Однако если объект пришёл с API, и оказался не той структуры, которой вы ожидали, то TS тут не спасёт. Есть несколько стратегий как минимизировать эти риски.
1. Фабричные функции.
В чем приимущество перед классами? Не писать new? Как делать extends? Различать по типу? И в чем проблема связываться с классом? В общем, давайте без фанатизма. Против фабричный функций ничего не имею против, но всему свое место. Не надо это лепить куда попало.
2. Прототип.
Ну ребят, ES6 не вчера же появился, и даже не позавчера. А вы продолжаете это лепить. Откройте для себя уже «class» в конце концов. Даже если вас заботит поддержка старых браузеров, то и TS и Babel давно уже могут собрать ваш код в ES5.
PS Да, классы не отменяют того, что вы должны понимать как работают прототипы под капотом и как работает наследование в JS.
7. Откройте для себя схемы и валидацию данных. Это избавит вас от ручной манипуляции. Посмотрите, к примеру, подход MongooseJS. Как там объявляются и валидируются данные.
Совет для новичков. Не стоит эти советы принимать к работе. Ознакомится — да, но не более.
class Person{
constructor(name){
this.name = name;
}
logName(){
console.log(this.name);
}
}
let p = new Person('Ivan');
btn.addEventListener('click', p.logName); // проблема this не person а уже button
// нужно явно указать контекст
btn.addEventListener('click', p.logName.bind(p));
С фабричными функциями нет проблем с this
const Person = function(name){
let state = {
name: name;
};
// Насчет extends наследование заменим композицией
return Object.assign({ logName: () => state.name },
Programmer(state),
Sportsmen(state)
);
}
const sportsmenIvan = Person('Ivan');
btn.addEventListener('click', p.logName); // никаких проблем с this
В вашем примере необходимо использовать:
class Person{
constructor(name){
this.name = name;
}
logName(){
console.log(this.name);
}
}
let p = new Person('Ivan');
btn.addEventListener('click', (e) => p.logName()); // нет магии, нет привязки.
Плюс, повышается читабельность кода.
С фабричными функциями нет проблем с thisНет проблем с this, потому что тут не использовали this?
Я вот тоже не совсем понимаю преимуществ фабричной функции перед классом. Как по мне это два совершенно разных паттерна и применяться они должны для разных ситуаций, а иногда даже совместно.
function createSpecies(type, name, gender) {
if (type === 'frog') {
return new Frog(name, gender)
} else if (type === 'human') {
return new Human(name, gender)
} else if (type == undefined) {
throw new Error('Cannot create a species with an unknown type')
}
}
const species = createSpecies('frog', 'sally', 'female');
// Проверка типов
species instanceof Frog // true
species instanceof Human // false
И, кстати, я не понял из текста, почему так важно обрабатывать именно JSON ошибки? Они как-то особо загадочно рушат приложения? И как try/catch помог бы автору избавиться от проблемы без исправления кода «внешнего пакета»?
7 рекомендаций по повышению надёжности JavaScript-кода