Comments 28
стрелочные функции позволяют писать более чистый и понятный код
вот только всё наоборот.
const getFirst = array => array[0];
Почему во многих статьях используются совершенно нелогичные примеры? Создавать функцию для получения первого элемента списка? Серьезно?
const getFirst = array => array[0];
getFirst(a)
вместо:
a[0]
Почему бы не использовать реальные примеры из реальных программ, чтобы даже новички видели преимущество тех или иных методов, и могли сразу применять «правильные» паттерны в разработке, вместо того, чтобы писать программы, состоящие из подобных примеров, и потом их исправлять, после того, как эти же более опытные разработчики (пищущие подобные статьи) укажут им на то, что их код «не оптимален»?
Более того, на массивах тогда уж логичнее делать примеры деструктуризации
[first, last] = [1, 2];
А для стрелочных функций просто приводить пример реализации на старом синтаксисе и новом или, например, реверс строки в одну строку:
const reverse = (str, i = 0) => (i >= str.length) ? '' : `${reverse(str, i + 1)}${str[i]}`;
const reverse = (str, i = 0) => (i >= str.length) ? '' : `${reverse(str, i + 1)}${str[i]}`;
Я изучаю JS. И я разбирался в этом примере из «риал прожект» дольше, чем читал статью, и всё равно не понял почему не написать так:
const reverse = (str, i = 0) => (i >= str.length) ? '' : `${reverse(str, i)}`;
Чтобы понять, придётся провести целое иследование в интернете.
Если написать так как вы написали — будет бесконечная рекурсия. Я вот другого не понимаю: зачем тут вообще интерполяция?
const reverse = (str, i = 0) => (i >= str.length) ? '' : reverse(str, i + 1) + str[i];
Правда, в таком виде оно все еще непонятно, как и любая замена цикла рекурсией или рекурсии циклом.
зачем тут вообще интерполяция?
Чтобы гарантированно работать со строкой. В случае вызова reverse('123')
без большого опыта работы с JS трудно предугадать как он себя поведёт и не вернёт ли 6, так как идёт конкатенация через плюс. Проверил, что в вашей реализации конкатенация отрабатывает как надо, но лучше перебдеть, чем недобдеть :)
...${reverse(str, i + 1)}...
идёт вызов какой-то встроенной функции «reverse()», которой, как я выяснил позже, не существует.
Но сейчас-то нахрена учебники на Хабр переписывать?
Второе заключается в том, что подход к работе со значением this в стрелочных функциях выглядит интуитивно понятнее, чем в обычных функциях.\
Нет — основные баги вылазят кораз потому, что стрелочные функции не имеют собственного зиз — а ещё и учитывая что транспайлеры и прочие упростители жизни могу интерпретировать каждый по своему — совсем непонятно почему автор мог вообще даже подумать о написаннии такого, не то что написать…
Однако у такого подхода масса минусов, которым посвящён этот материал.
В подобных случаях, вместо стрелочных функций, используйте обычные функции, и, если нужно, привязывайте к ним экземпляр объекта в конструкторе:
Проблемы, обсуждаемые по приведённой вами ссылке как раз вызваны тем, что метод прописывается в инстанс объекта (каждый раз при создании), а не в его прототип. А такой "болезни" подвержен и ваш пример с
this.handleClick = this.handleClick.bind(this);
Ну и про производительность там тоже в комментариях намекнули, что какие-то у него странные тесты, что стрелочная функция вышла медленней функции после .bind, они примерно одинаковые по производительности. Автор потом конечно приводит ссылку на тест, но по ней отдаётся 404 =(
Шел 2018 год.
class Counter {
counter = 0;
handleClick() {
this.counter++;
}
constructor() {
this.handleClick = this.handleClick.bind(this);
}
}
мне хочется оторвать руки написавшему это…Ну во-первых, не стандарт. Какой мне плагин к бабелю нужно подрубить, чтоб это заработало? Проще поправить:
class Counter {
constructor(elem) {
this.counter = 0;
this.handleClick = this.handleClick.bind(this);
// очевидно нужно еще событие навесить, чтоб заработало
elem.addEventListener('click', this.handleClick);
}
handleClick() {
this.counter++;
}
}
теперь заработало… вот только я таких счетчиков решил 500 штук повесить на странице, и… забью память на 500 штук однотипных функций, единственная роль которых запомнить контекст для вызова метода. Уж не лучше тогда было стрелочник в конструкторе повесить:class Counter {
constructor(elem) {
this.counter = 0;
this.handleClick = () => this.counter++;
elem.addEventListener('click', this.handleClick);
}
}
уже лучше, вот только в памяти по прежнему 500 функций… Нехорошо.Почему бы не реализовать интерфейс EventListener и использовать его?
class Counter {
constructor(elem) {
this.counter = 0;
elem.addEventListener('click', this);
}
handleEvent() {
this.counter++;
}
}
Теперь идеально, на все 500 объектов в памяти одна единственная функция в прототипе.Потребовалось нам однажды задействовать для внешнего класса Object.defineProperty
(дело было в Cocos Creator, хаков там и так порой хватало из-за слегка долбанутой системы его взаимодействия с TypeScript). Да не простой, а с парой из геттера и сеттера. Спокойно пишу так, как успел привыкнуть:
{
get: () => ...,
set: (value) => ...
}
И только после пары падений до меня доходит… В общем, это навскидку единственное место, где мне реально потребовалось сознательно отказаться от стрелочной функции.
Стрелочные функции в JavaScript: зачем они нужны, как с ними обращаться, когда ими стоит пользоваться, а когда — нет