Функциональное программирование: как правильно объединить оператор извлечения элементов?

Одна особенность в JavaScript, кажется, позволяет мне уклоняться от «правильного» пути.

Вместо того, чтобы писать d.foo и d.bar, можно также писать d["foo"] и d["bar"].

В большинстве сценариев использования подойдет любая форма, но в следующем коде

function f(myscale, foo_or_bar) {
    blah.attr(myscale(d => d[foo_or_bar]));
}
f(foo_scale, "foo");
f(bar_scale, "bar");

Я могу отправить строку, чтобы сигнализировать о том, что к тому или иному члену следует получить доступ.

Конечно, здесь у меня есть только одно утверждение (blah.attr), которое не гарантирует определения/использования функции, но на практике оно более существенно и требует общего определения.

Действительно, приведенный выше код кажется настолько плохим, что было бы не намного хуже отправить логический флаг is_it_foo и написать оператор if для выбора между d.foo и d.bar.

Каков правильный (функциональное программирование) способ объединения двух строк

blah.attr(foo_scale(d => d.foo));
blah.attr(bar_scale(d => d.bar));

в один?

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

Обновлять

В основном я ищу эксперта по Лисп или Схема, который затем изучил JavaScript. Для этого человека вопрос будет тривиальным и мгновенным упражнением. Если, как и я, ваша гравитация все еще находится в мире C++/Java, пожалуйста, подождите вместе со мной, пока кто-нибудь не прольет свет. (Для «близких» избирателей я с радостью удалю вопрос, если люди из Scheme/Lisp также укажут, что в этом нет смысла и что передача строки для извлечения члена — это нормально.)

Нет ничего плохого в доступе к свойствам объекта с помощью вычисляемых строк.

Pointy 11.06.2019 16:31

Произвольный f, неопределенный .blah, неопределенный, .attr, неопределенный foo_scale и bar_scale... Пока вы не поделитесь фактическим кодом и контекстом вокруг него, мы можем только догадываться или предполагать вашу цель. Fwiw, JavaScript и Scheme принадлежат мне, и ваши намерения мне совершенно неясны. "Объединить две строки... в одну" - может быть, показать схему, эквивалентную тому, что вы пытаетесь сделать? Как написано в вашем посте, bar.attr полагается на побочный эффект, потому что вы не используете его возвращаемое значение для чего-либо - это само по себе уже не похоже на Scheme, который охватывает функциональный стиль.

Mulan 11.06.2019 17:33

Другими словами, укажите минимальный воспроизводимый пример. Каковы входные данные для вашей предполагаемой программы? Каков ожидаемый результат?

Mulan 11.06.2019 17:35

Чтобы добавить, ваш вопрос отталкивает опытных программистов JavaScript и Scheme. Первой группе сообщается, что вы заинтересованы в ответе другой группы. Для второй группы, если они не понимают вашего вопроса, они не должны быть экспертами в своей группе. У каждого языка есть свои собственные идиомы и лучшие практики, и вы уже признали, что являетесь новичком в JavaScript; так почему вы думаете, что знаете ответ или от кого он должен исходить?

Mulan 11.06.2019 17:46

В вашем вопросе нет Scheme или Lisp. Теги, которые вы добавили при редактировании, будут удалены, поскольку вы используете их только для передачи своего вопроса более широкой аудитории. Даже тег functional-programming является спорным, поскольку в вашем сообщении не соблюдаются функциональные стили или дисциплины.

Mulan 11.06.2019 17:52
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
5
83
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Для каждого ключа foo, если у вас есть уникальная функция сопоставления foo_scale, то то, что вы делаете в настоящее время, является правильным путем:

blah.attr(foo_scale(d => d.foo);
blah.attr(bar_scale(d => d.bar);

Это скорее шаблон проектирования кода, чем функция Javascript. Так как это не только улучшит читаемость кода, но и позволит вам изменить функцию любой клавиши по желанию.

Но скажем, все ваши ключи сопоставляются с одной функцией отображения scale, вы можете сделать:

const keys = ["foo", "bar"]

keys.forEach((key) => {
    blah.attr1(scale(d => d[foo_or_bar]);
    blah.attr2(scale2(d => d[foo_or_bar]);
    blah.attr3(scale3(d => d[foo_or_bar]);
})

В идеале это хороший шаблон, и его можно использовать, если вы можете обобщить общие шаблоны в один метод scale

Учтите, что blah.attr — это место для тридцати строк кода. Закончив с foo, вы копируете и вставляете тридцать строк, меняя правильные foos на bars, но затем останавливаетесь. Вы знаете, что поддерживать шестьдесят строк кода будет большой головной болью, отсюда и вопрос.

Calaf 11.06.2019 16:41

Но есть ли у bar другой метод bar_scale, подобный тому, как у foo есть foo_scale ?

Easwar 11.06.2019 16:42

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

Easwar 11.06.2019 16:44

Предположим, что все ключи могут проходить через один и тот же преобразователь, тогда мой второй фрагмент выше должен работать нормально. Вместо 3 строк вставьте свои 30 строк. Он будет повторяться для всех ключей.

Easwar 11.06.2019 16:45
Ответ принят как подходящий

Вместо того, чтобы передавать имя свойства в виде строки, вы можете также передать функцию получения свойства в качестве аргумента для f:

function f(myscale, get) {
    blah.attr(myscale(get));
}
f(foo_scale, d => d.foo);
f(bar_scale, d => d.bar);

Бинго... но теперь вы отправляете параметры два. Как вы их комбинируете?

Calaf 11.06.2019 16:42

@Calaf Я думал, что параметр scale не имеет отношения к вопросу. Конечно, вы можете объединить их в объект (не очень функциональный), но нет ничего плохого в том, чтобы иметь два параметра. В этом конкретном случае вы, конечно, можете просто использовать f(foo_scale(d => d.foo)) и f(bar_scale(d => d.bar)) с f = blah.attr, но я думаю, вам нужно опубликовать свой полный код, чтобы я мог правильно судить. (А откуда берутся foo_scale и bar_scale, связаны ли с ними уже названия свойств?)

Bergi 11.06.2019 16:48

Код в вопросе был слишком коротким. Скорее всего, сам d тоже нужно отправить, в зависимости от контекста. Несмотря на это, функция доступа — правильная идея.

Calaf 19.07.2019 12:56

Другие вопросы по теме