Как стать автором
Обновить

Комментарии 72

почему я люблю scala


коротко


val filteredHeroes = femaleHeroes.filter( _.sex == "f")

читаемо


def isFemale(x:Heroes) = "f" == x.sex 
val filteredHeroes = femaleHeroes.filter(isFemaile)

Так в JS так же:


const filteredHeroes = femaleHeroes.filter(({ sex }) => sex === "f")

const isFemale = ({ sex  }) => sex === "f"
const filteredHeroes = femaleHeroes.filter(isFemale)
Не разрушайте иллюзии. Пусть живут в эльфийском мире Scala/Haskell/F# и думают, что JS для орков.

Имею мнение, что вы что-то додумываете

НЛО прилетело и опубликовало эту надпись здесь
давайте лучше подумаем, в каком языке этого нет
Pascal
ну если принять во внимание то, что Pascal->Object Pascal ->Delphi
тогда и там можно найти и упорядоченные списки, и сортировки, и бинарный поиск…
я подумал, может delphi — это слишком притянуто за уши? дополнительно нагуглил freepascal rtl tlist http://www.freepascal.org/docs-html/rtl/classes/tlist.indexof.html
Заранее извиняюсь за, возможно, глупый вопрос, но зачем фигурные скобки внутри списка аргументов? Учитывая, что можно вообще без скобок. Или я что-то путаю?

Если без скобок, то в функцию передастся объект. А со скобками сразу произойдет деструктуризация.

Это деструктурирование.


можно написать так


femaleHeroes.filter((hero) => hero.sex === "f")

А можно не писать hero а достать из него только поле sex, которое нам нужно


femaleHeroes.filter(({ sex }) => sex === "f")
Ох, там же объект передается, тогда логично. Как-то я не задумался, что аргумент — объект.

Мой косяк, спасибо. :)
Если аргумент один, то можно еще и без круглых скобок. :) Вот так:
femaleHeroes.filter( hero => hero.sex === "f")

Это какое-то введение в underscore/lodash для самых маленьких.

старый добрый цикл for…of

Улыбнуло :) for...of, который буквально недавно (в ES6) появился

С массивами то все понятно. А как быть с объектами?
Например, есть объект:
const modes = {
    air: false,
    road: true,
    sea: false
};

Нужно получить новый объект, в котором будут только те поля, которые в исходном были «true».
Т.е:
const newModes = {
    road: true
};

Очень часто такая штука используется в мультиселектах.
Можно так:
const modes = {
    air: false,
    road: true,
    sea: false
};

const newModes = Object.keys(modes)
  .filter(key => modes[key])
  .reduce((prev, key) => {
    return {
      ...prev,
      [key]: modes[key]
    }
  }, {});
Благодарю, как-то не додумал до этого.
Жаль что в JS нету map/filter/reduce для объектов. Думаю очень удобно было бы иметь что-то типа:
const newModes = modes.filter( (value, key, obj) => value);
или
const newModes = modes.map( (value, key, obj) => ({[key]: !value}));
Читайте выше. Я про объекты говорил.
В таких ситуациях обычно не обычные объекты нужны, а Map.

Да, но их можно написать и самому.


Наверняка есть и сторонние решения :)

Можно еще чуть укоротить =)


const newModes = Object.keys(modes)
.reduce((prev, key) => modes[key] ? ({ ...prev, [key]: modes[key] }) : prev, {});
Может я не так понял, но один вариант такой:
let { road: fieldValue } = modes,
     newObj = {
         road: fieldValue
     };

TLDR:
Работая с массивами старайтесь использовать нативный API (forEach, map, filter, reduce), не делайте код избыточным.

ИМХО, конечно, но это уже функциональное программирование.
На JavaScript? Неожиданно…
JavaScript, похоже, единственный язык, на котором можно программировать как хочешь
А я все думал, почему мне С# нравится… а вот оно что…
Английская статья имеет более обстоятельную табличку

похожи на лежащие на боку буквы «V»
Любому программисту знаком оператор ">" :)
Извиняюсь, за тупость, но поясните, чем рекурсия выгоднее цикла? Быстрее работает? жрет меньше памяти? или типо удобнее читать код?

Я бы сказал, ни то, ни другое, ни третье. Просто циклы/рекурсия – это низкоуровневая абстракция, которую можно инкапсулировать в отдельной функции, чтобы детали имплементации не смешивались с бизнес-логикой.


Тот же lodash внутри и использует много циклов.

Тот же lodash внутри и использует много циклов.

Между тем jdalton удалил из кодовой базы lodash внутренние модули на циклах и заменил их на нативные. Обновление до v5 будет болезненным.

Вот только нативные методы в разы медленнее циклов. Сомневаюсь, что он это сделает.

Что имеется в виду? Тело цикла — произвольный набор инструкций или одна функция, возможно анонимная с "самовызовом"?

Рекурсивное решение выглядит весьма элегантно. Всего пара строчек кода и минимум отступов. Но рекурсивные реализации алгоритмов обычно используют с большой осторожностью, кроме того, они отличаются плохой производительностью в старых браузерах.


Где тут сказано про выгоду? :)
Видать пропустил этот абзац, но спасибо за объяснение
НЛО прилетело и опубликовало эту надпись здесь
Что за трамплины? Первый раз встречаю это слово вместе с рекурсией и монадами.
Как-то так
Насколько я могу вспомнить, все нормальные введения в тему функционального программирования начинаются с показа функций map, filter и reduce.

Про javascript еще всегда интересны статьи на тему «Почему в javascript есть функция eval, откуда она там взялась, зачем она там нужна, и почему такой функции нету в императивных языках вроде Pascal и Java».
Это очень круто, что есть люди, которые задумываются над такими вопросами. Когда пишешь код страницами, такие вещи запросто улетучиваются из головы (сыплю голову пеплом).
В названии обещали избавить меня от циклов а в результате упаковали циклы в методы и функции =(
Javascript без циклов — это в идеальном случае purescript, в хорошем случае livescript, и на худой конец — coffeescript
Чего только не придумают, лишь бы на ELM не писать.

Вредная статья, как и каждая вторая про функциональное программирование в JavaScript. Подчеркиваю — в JavaScript.


JavaScript не рассчитан на функциональное программирование, хоть и с виду кажется, что расчитан. Да, есть хай-ордеред функции, да, всякие там лямбды и замыкания. Но если вы пишете [я понимаю, что это перевод, если что], что циклы не нужны, а вот функции нужны, то советую сравнить скорости работы императивного подхода в JS и функционального. Просто возмите и перепишите любой цикл на рекурсию. И сравните. Ведь в функциональных языках, на сколько я знаю, цикл замещается рекурсией? Ну так вот, вы скорее всего расстроетесь и немного загрустите.


Скажем так, против ФП никаких нареканий нет, но оно должно быть уместно и применено в тех языках, которые расчитывают именно на функциональный подход изначально и не являются просто "поддерживаемой парадигмой", а внутренним устройством.


Лично мой подход — это здравое комбинирование императивного и функционального. Функциональное, обычно, описывает архитектуру, какой-то паттерн. А вот конкретные имплементации отдельных функций/методов уже не брезгуют циклами и прочими вещами, далекими от ФП и близкими императивному подходу.


Тем самым сохраняется чистая архитектура и здравая скорость.

НЛО прилетело и опубликовало эту надпись здесь
Ведь в функциональных языках, на сколько я знаю, цикл замещается рекурсией?
Мало знаете, получается. В 95% случаев цикл замещается функцией map, reduce или filter. Рекурсия в этой роли — это редкий изврат типа факториала, уже для чего-то чуть более сложного типа чисел Фибоначчи цикл просто не подойдёт.

Нет, это не так. Map, filter, reduce (а также every и some) мы используем при работе с массивами. Но кроме массивов есть еще какие-то императивные алгоритмы, которые, например, просто должны делать что-то некое количество раз. И не имеют отошения к массивам вообще.

Императивные алгоритмы лучше реализовывать императивно :)
Выполнение некоторой чистой функции несколько раз бессмысленно. Есть близкая абстракция к циклу for — развертка (unfold). Но опять же, это функция, и имеет возвращаемое значение.

Одними чистыми функциями нормальную программу не написать. Хотя есть варианты обходиться без циклов и для "грязных", если в языке есть генераторы или что-то подобное, а то и просто массив создавать, типа (new Array(7)).foreach(...)

НЛО прилетело и опубликовало эту надпись здесь
Array.apply(0, {length:7}).forEach(...)

Для таких целей существует Array.from


Array.from({length: 7}).forEach(...)
НЛО прилетело и опубликовало эту надпись здесь

Да, но и forEach это IE >= 9.


Кстати, еще из современного:


[...Array(7)].forEach(...)
НЛО прилетело и опубликовало эту надпись здесь

Навскидку написал, по памяти, просто для демонстрации идеи — создать массив нужной длины и пройтись "по нему".

В 95% случаев цикл замещается функцией map, reduce или filter.

При этом map & filter реализуются через reduce, а reduce — через рекурсию )))

Ну вообще логично — чем выше уровень, тем меньше эффективность(имея ввиду скриптовые языки), и она лишь тогда высока, когда задействование прослойки между уровнями, дороже решения внутри более высокого уровня.

Статья эта, туториал, призванный показать применение функций, не так давно интегрированных(ну как минимум, по мнению автора не так давно). Так как всякий туториал, нацелен на тех, для кого его содержание окажется чем-то новым. То с одной стороны, сомнительна необходимость перевода для хабра, с другой, тема не подается к обсуждению.

Тем не менее, она сама по себе цепляет некоторых, и вас в частности. Поэтому для вас утратило значение, что речь в статье сплошь о массивах, другое по сути и не рассматривалось.
И также, шаблон статьи, сначала сделаем плохо, а потом исправим, вовсе не красит и не предлагает реально использовать рекурсию.
Насколько я читал, изначально просто хотели сделать императивный диалект Scheme для скриптования браузера Netscape по типу AutoCAD'а, но потом пришли настойчивые маркетологи и сказали что нужен скриптовый язык, похожий на C и Java.

Из циклов for и while можно выйти в любой момент. Иногда это нужно.

НЛО прилетело и опубликовало эту надпись здесь

Вот только лучше уж цикл, чем увидеть такое в продакшн-коде.

НЛО прилетело и опубликовало эту надпись здесь
function conditionBreak(condition, body){
  var state = true;
  typeof condition !== 'function' && (condition = function(){});
  typeof body !== 'function' && (body = function(){});
  return function(){
    if (state && condition.apply(undefined, arguments)) {
      body.apply(undefined, arguments);
    } else {
      state = false;
    }
  }
}

[1, 2, 3, 4, 1, 2, 5].map(conditionBreak((n) => {
  return n <= 3;
}, (n) => {
  console.log(n);
}));

Лучше уж как-нибудь вот так. В отличии от .filter он не отбирает, а реально "выбрасывает" при первом неудовлетворяющем условии.

НЛО прилетело и опубликовало эту надпись здесь

Я же написал, чем это отличается от фильтра. Фильтр, если, например, мы имеем массив со значениями 1, 2, 3, 1, 2, 3 и правило выхода "n <= 2", вернет массив со значениями 1, 2, 1, 2.
В вышеописанной функции conditionBreak остановка произойдет после первой тройки, то есть значения будут 1, 2 и все. Это более близко поведению break оператора цикла.

НЛО прилетело и опубликовало эту надпись здесь
Зарегистрируйтесь на Хабре, чтобы оставить комментарий