Comments 32
1) группировать по функционалу
2) условия if(err) reject
3) примеры со стрелочными функциями и ненужными переменными.
ES5 тяжело давался всегда, поэтому ES6 освоил быстро и с большим удовольствием!
1. Стоит помнить, что если собираетесь поддерживать IE 11 или Safari до 10й ветки, то использовать их не получится. Ещё некоторые браузеры под Android могут подсунуть свинью, включая довольно популярный UC Browser. Opera Mini тоже всё ещё используют (~3%!) и там их тоже нет. Если тебе не интересны 10~15% владельцев мобильных телефонов, то можешь использовать arrow-функции. Иначе стоит подождать, пока их поддержку сделают как минимум в UC Browser.
2. Они не инициализируют this до момента вызова. Это можно применить для создания функций, обращающихся к this в теле конструктора класса, созданного на основе другого класса, и до вызова super в конструкторе наследуемого класса (в наследуемом классе нельзя вызывать this до вызова super — кидает ошибку). Хотя зачем так вообще может понадобиться сделать для меня загадка и, наверное, лучше так не делать.
3. Данный тип функций невозможно использовать в качестве конструктора. У них даже prototype нет, чтоб это было возможно.
4. В теле этих функций нельзя использовать arguments, new.target и super. Все они наследуются из контекста вызова функции. Последние два в них вообще бессмысленно вызывать в виду пункта 3. Если умудритесь сделать все функции arrow-функциями, то попытка обратиться к arguments и вовсе приведёт к ошибке так-как
эта переменная не будет создана ни в одном контексте. В любом случае лучше не используйте arguments внутри arrow-функций если только не хотите умышленно запутать свой код.
Насчет стиля кода по ES6, тут как по мне, нужно в меру. Мало того, что некотый «сахар» дороже в вызове, дак еще и уменьшает читаемость в некоторых случаях, особенно, когда код превращается в микс из букв и специальных символов.
Не всегда выпиливание «лишних» переменных способствует восприятию. Когда видишь только агрегирование данных, без промежуточных переменных, куда сложнее держать в голове всю цепочку действий, тогда как с промежуточными переменными легче понимать что творится в коде. Сразу же, сюда — о пункте про if(!value) — чтобы оперировать с отдельной инвертированной переменной, ее нужно объявить, что противоречит пункту о ненужных переменных. Как то автор(не перевода) не смог себе не противоречить.
В остальном конечно все здраво, хотя есть парочка примеров, не сильно вписывающихся.
Когда видишь только агрегирование данных, без промежуточных переменных, куда сложнее держать в голове всю цепочку действий, тогда как с промежуточными переменными легче понимать что творится в коде.
Не холивора ради, но таки подобные задачи еще лучше решаются через декомпозицию. Если ваша функция состоит из нескольких шагов, которые совершенно очевидно делятся на части пресловутыми промежуточными переменными, то вы очевидно сможете разбить ее на несколько функций, каждая из которых будет удовлетворять условию.
Декомпозиция сама по себе не подразумевает вынесение каждой строчки в отдельную функцию, вы просто доводите мой пример до абсурда и он, разумеется, теряет свой смысл.
Смотрите, допустим у нас есть некоторых размеров функция, в которой присутствует несколько локальных переменных. Насколько я понял, автор оригинальной статьи называет «лишними» те переменные, от объявления которых можно избавиться, никоим образом не повлияв на рантайм приложения.
Например:
var buzz = function () {
var data = getSomeData();
var result = doSomething(data);
return result;
}
Некоторые линтеры сами предложат заменить это на
var buzz = function () {
return doSomething(getSomeData());
}
А в каком-нибудь абстрактном функциональном языке это будет выглядеть и вовсе так:
buzz = getSomeData * doSomething
Но за этими getSomeData и doSomething вовсе не обязана стоять одна строчка кода (в таком случае ее и так можно заинлайнить, наверное).
Опять же, насколько я понял, автор любит функциональное программирование, а во многих функциональных языках переменные отстутсвуют в принципе. Если себя «программировать» под их регулярное использование, то изучение этих языков может стать большой проблемой.
Потому что сегодня result сразу возвращается как есть. А завтра он будет обработан и заброшен в структуру, которая и будет возвращаться. Поэтому для себя я принял правило — если в каком-то результате есть смысл, его лучше сохранить. Компилятор сам потом всё оптимизирует, а вот код рефакторить будет проще.
По мне лучше функция из нескольких шагов, но в пределах одного экрана, чем прыгать по файлам и функциям не теряя контекст.
одна функция — одна задача
Неужели эти общие принципы нельзя применить к другим языкам?
Мне почему-то кажется (т.е. лень проверять) что на том же Питоне все примеры можно практически один к одному переписать.
(а так — солидарен, хотя имхо и вполне очевидно во многом)
ES5 имеет более очевидный синтаксис. Стрелки ес6 мой глаз видит как выражения, а не как функции. А присваивания в аргументах стрелок, да еще и без return вообще выглядит как бардак. Единственная полезность стрелок — сохранение this. IMHO.
Ликвидация «избыточного» кода далеко не всегда приводит к улучшению читаемости. Кроме того, иногда бывает так — сразу после сокращения кажется, что код стал гораздо чище и элегантнее. Но когда ты возвращаешься к нему через пару месяцев, то краткость превращается в ребус, на расшифровку которого требуется ощутимое лишнее время.
Например, приводимый в статье пример с каррированием. Приведенный в статье код, на мой взгляд, плохо читается. Двойная стрелка
const add2 = a => b => a + b
потребует некоторого времени на осмысление, а вот следующая строчка const inc = add2(1)
и совсем нехороша: через пару месяцев, взглянув на нее, сможете ли вы с ходу сказать, что inc — функция?и совсем нехороша: через пару месяцев, взглянув на нее, сможете ли вы с ходу сказать, что inc — функция?
А вы правда думаете, что люди, которые пишут такой код — поддерживают его целых два месяца?
А чего здесь такого? Вот пример с Github: библиотека recompose, там большая часть кода основана на каррировании.
Если это нормально оформить в документации, то проблем не возникает.
В том конкретном примере, что я привел, достаточно один раз понять, почему в проекте пишется a => b => {}
вместо (a, b) => {}
и после этого код читается вполне неплохо.
func(a)(b)
ты не будешь знать — это уже итоговое значение, или всё ещё функция, которая ждет недостающий аргументTypescript вам в помощь! С ним такие вещи узнаются легко.
Если же типов нет, то поможет здравая логика, например соглашение, что все функции из модуля Х возвращают еще одну функцию, например add(1)(2)
. Если же arity у каждой функции разное, то работать с этим неудобно, с этим соглашусь
А что именно вы хотите? Без строгих типов точно узнать, что вернется из функции, не получится, будь там каррирование или нет.
add(1)(2)
обычно считают типизацию порождением сатаны.И, обычно, на такое получаешь бредовый ответ из разряда: «ну так помоги сообществу, напиши сам». Напишу, конечно, куда я денусь, но это рак JS, что авторы библиотек не спешат их типизировать и почему это меня не должно возмущать?
Я как раз разрабатываю на React и TS, так что прекрасно знаю «состояние сообщества».
JavaScript: элементы стиля