Как применить свойства объекта к функциям?

Я хочу применить разные функции к некоторым свойствам объекта. Допустим, у меня есть этот объект:

const person = {
  name: 'John',
  age: 30,
  friends: [],
};

и у меня есть несколько функций, которые я хочу применить к этим свойствам:

const upperCase = str => str.toUpperCase() //for the name

const add10 = int => int + 10 // for the age

const addFriend = (value,list) => [...list,value] // adding a friend

и вот должен быть результат:

const person = {
  name: 'JOHN',
  age: 40,
  friends: ['Lucas']
}

Как лучше всего добиться этого с помощью функционального программирования и бесплатного использования точек, и если бы вы могли включить примеры с использованием Ramda, я был бы признателен, спасибо!

2 ответа

Решение

С Ramda вы смотрите на evolve функция:

Создает новый объект путем рекурсивного развития мелкой копии объекта в соответствии с функциями преобразования. Все непримитивные свойства копируются по ссылке.

Возможно, вам потребуется определять функции "преобразования" на лету; Бьюсь об заклад, вы не хотите добавлять "Лукаса" как друга каждого человека. Надеюсь, этого достаточно, чтобы вы начали.

const transform =
  evolve(
    { name: toUpper
    , age: add(10)
    , friends: prepend('Lucas')
    });
    
    
console.log(

  transform(person)

);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {evolve, toUpper, add, prepend} = R;</script>
<script>
const person =
  { name: 'John'
  , age: 30
  , friends: []
  };
</script>


Бесточечный стиль - не единственный способ

⚠️

Обратите внимание, что мне удалось реализовать этот безточечный стиль, потому что я мог жестко кодировать каждую функцию преобразования. Если вам нужно создать объект трансформации "на лету", то использование этого стиля без точек, вероятно, будет быстро нечитаемым.

Как обычно, customcommander дает отличный ответ. Рамдаevolve предназначен именно для этого и в простом случае может дать совершенно бессмысленный ответ.

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

Итак, если у вас не было под рукой Ramda, вы могли бы легко написать собственную версию этой функции следующим образом:

const evolve = (spec, keys = Object .keys (spec)) => (obj) => 
  Object .entries (obj) .reduce ( 
    (a, [k, v]) => ({...a, [k]: keys .includes (k) ? spec [k] (v) : v})
    , {}
  )

const upperCase = str => str.toUpperCase() //for the name
const add10 = int => int + 10 // for the age
const addFriend = (value) => (list) => [...list,value] // adding a friend
const person = {name: 'John', eys: 'blue', age: 30, friends: [], hair: 'red'}

console .log (
  evolve ({name: upperCase, age: add10, friends: addFriend('Lucas')}) (person)
)

Это далеко не самый производительный код. Отличная статья от Rich Snapp объясняет, почему и как это исправить. Но я лично буду придерживаться этого, если это не станет узким местом в моем приложении.

Конечно, как указывает customcommander, для каждой из ваших помощников есть функции Ramda: toUpper, add, append (ближе к приведенной выше реализации, чем prepend.)

Более полное обсуждение темы VLAZ, поднятой в комментарии, можно найти в /questions/27556959/pochemu-narodnaya-skazka-i-ramda-takie-raznyie/27556964#27556964.

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