Pull to refresh

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()», которой, как я выяснил позже, не существует.
Ну представьте, что вам надо сделать arr.map(x => x[0]);
Вот именно эту строчку и было бы неплохо увидеть в статье.
Когда я был маленьким, всего этого нельзя было прочитать на developer.mozilla.org.
Но сейчас-то нахрена учебники на Хабр переписывать?
Я пологаю для истории. Пройдет много времени и спецификация языка поменяется, странички на developer.mozilla.org обновятся. А эта статья так и останется на хабре. Можно будет зайти сюда, почитать, по ностальгировать. Вспомнить времена когда JS был еще тёплым, ламповым.
Все какие-либо структурные изменения уходят в deprecated метку, все равно для саппорта будут оставлять старые реализации
Пока такие статьи плюсуют их будут здесь постить.
Второе заключается в том, что подход к работе со значением this в стрелочных функциях выглядит интуитивно понятнее, чем в обычных функциях.
\
Нет — основные баги вылазят кораз потому, что стрелочные функции не имеют собственного зиз — а ещё и учитывая что транспайлеры и прочие упростители жизни могу интерпретировать каждый по своему — совсем непонятно почему автор мог вообще даже подумать о написаннии такого, не то что написать…
Транспайлеры не могут интерпретировать стрелочные функции каждый по-своему, потому что у стрелочных функций есть вполне конкретное поведение, прописанное в стандарте.
Было такое что после обновления версии транспайлера — перестал работать код — причина оказалась в неправильная интерпретация замыканий в методе функции — не помню какой транспайлер использовался — но было)
А вот бы статья начиналась со слов о том, когда была введена эта фишка и какие версии браузеров её теперь поддерживают.
Однако у такого подхода масса минусов, которым посвящён этот материал.
В подобных случаях, вместо стрелочных функций, используйте обычные функции, и, если нужно, привязывайте к ним экземпляр объекта в конструкторе:

Проблемы, обсуждаемые по приведённой вами ссылке как раз вызваны тем, что метод прописывается в инстанс объекта (каждый раз при создании), а не в его прототип. А такой "болезни" подвержен и ваш пример с


this.handleClick = this.handleClick.bind(this);

Ну и про производительность там тоже в комментариях намекнули, что какие-то у него странные тесты, что стрелочная функция вышла медленней функции после .bind, они примерно одинаковые по производительности. Автор потом конечно приводит ссылку на тест, но по ней отдаётся 404 =(

Нет, вариант с bind этим проблемам не подвержен, потому что создает два разных метода: один обычный и остается в прототипе, а второй — привязанный и хранится в объекте.
Хм, да, тут вы правы, что-то я не подумал об этом.
Каждый раз, когда я вижу подобный код:
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) => ...
}

И только после пары падений до меня доходит… В общем, это навскидку единственное место, где мне реально потребовалось сознательно отказаться от стрелочной функции.

Sign up to leave a comment.