Одна особенность в 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 также укажут, что в этом нет смысла и что передача строки для извлечения члена — это нормально.)
Произвольный f, неопределенный .blah, неопределенный, .attr, неопределенный foo_scale и bar_scale... Пока вы не поделитесь фактическим кодом и контекстом вокруг него, мы можем только догадываться или предполагать вашу цель. Fwiw, JavaScript и Scheme принадлежат мне, и ваши намерения мне совершенно неясны. "Объединить две строки... в одну" - может быть, показать схему, эквивалентную тому, что вы пытаетесь сделать? Как написано в вашем посте, bar.attr полагается на побочный эффект, потому что вы не используете его возвращаемое значение для чего-либо - это само по себе уже не похоже на Scheme, который охватывает функциональный стиль.
Другими словами, укажите минимальный воспроизводимый пример. Каковы входные данные для вашей предполагаемой программы? Каков ожидаемый результат?
Чтобы добавить, ваш вопрос отталкивает опытных программистов JavaScript и Scheme. Первой группе сообщается, что вы заинтересованы в ответе другой группы. Для второй группы, если они не понимают вашего вопроса, они не должны быть экспертами в своей группе. У каждого языка есть свои собственные идиомы и лучшие практики, и вы уже признали, что являетесь новичком в JavaScript; так почему вы думаете, что знаете ответ или от кого он должен исходить?
В вашем вопросе нет Scheme или Lisp. Теги, которые вы добавили при редактировании, будут удалены, поскольку вы используете их только для передачи своего вопроса более широкой аудитории. Даже тег functional-programming является спорным, поскольку в вашем сообщении не соблюдаются функциональные стили или дисциплины.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Для каждого ключа 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, но затем останавливаетесь. Вы знаете, что поддерживать шестьдесят строк кода будет большой головной болью, отсюда и вопрос.
Но есть ли у bar другой метод bar_scale, подобный тому, как у foo есть foo_scale ?
Если это так, то он не будет хорошо масштабироваться. Предположим, у вас есть 100 ключей, у каждого из которых есть свой метод key_scale, тогда либо у каждого ключа очень разное назначение, либо что-то не так в логической абстракции.
Предположим, что все ключи могут проходить через один и тот же преобразователь, тогда мой второй фрагмент выше должен работать нормально. Вместо 3 строк вставьте свои 30 строк. Он будет повторяться для всех ключей.
Вместо того, чтобы передавать имя свойства в виде строки, вы можете также передать функцию получения свойства в качестве аргумента для f:
function f(myscale, get) {
blah.attr(myscale(get));
}
f(foo_scale, d => d.foo);
f(bar_scale, d => d.bar);
Бинго... но теперь вы отправляете параметры два. Как вы их комбинируете?
@Calaf Я думал, что параметр scale не имеет отношения к вопросу. Конечно, вы можете объединить их в объект (не очень функциональный), но нет ничего плохого в том, чтобы иметь два параметра. В этом конкретном случае вы, конечно, можете просто использовать f(foo_scale(d => d.foo)) и f(bar_scale(d => d.bar)) с f = blah.attr, но я думаю, вам нужно опубликовать свой полный код, чтобы я мог правильно судить. (А откуда берутся foo_scale и bar_scale, связаны ли с ними уже названия свойств?)
Код в вопросе был слишком коротким. Скорее всего, сам d тоже нужно отправить, в зависимости от контекста. Несмотря на это, функция доступа — правильная идея.
Нет ничего плохого в доступе к свойствам объекта с помощью вычисляемых строк.