Как подражать loda sh .set с Рамдой - PullRequest
1 голос
/ 29 января 2020

Я учу Рамду, и я в замешательстве. Я хочу сделать функцию набора, которая работает аналогично функции loda sh .set. Тем не менее, когда я пытаюсь сделать следующее на пути, который существует в объекте, он, кажется, работает как задумано, но когда я использую его для создания нового пути, он добавляет этот странный массив.

const R = require('ramda')

const set = (object, path, value) => R.set(R.lensPath(path), value, object);

const foo = {
  moo: {
    goo: 'goo'
  }
}


set(foo, ['moo', 'goo', 'boo'], 'roo'); // { moo: { goo: { '0': 'g', '1': 'o', '2': 'o', boo: 'roo' } } }

Так что результат: // {moo: {goo: {'0': 'g', '1': 'o', '2': 'o', boo: 'roo'}}}

Когда я ожидал, что это будет: // {moo: {goo: {boo: 'roo'}}}

Почему он добавляет эти символы по индексу? Как мне выполнить sh функцию loda sh .set с Рамдой?

1 Ответ

3 голосов
/ 29 января 2020

Это похоже на нежелательное поведение. Зачем кому-то желать, чтобы Рамда заставил струну?

Я думаю об этом как о другом вопросе. Вы пишете код, который должен делать что-то неопределенно эквивалентное foo.moo.goo.boo = 'roo', когда foo.moo.goo - строка. Это, конечно, привело бы к ошибке, такой как Cannot create property 'boo' on string 'goo'.

Лода sh отвечает на это, говоря что-то вроде «О, вы, должно быть, имели в виду foo.moo.goo = {boo: 'roo'}». Это вполне разумное предположение. Но это предположение. Должна ли библиотека вместо этого выдать ошибку, подобную приведенной выше? Это, вероятно, было бы самой логичной вещью.

Рамда (отказ от ответственности: я один из ее авторов) делает другой выбор. Предполагается, что вы имели в виду то, что вы сказали. Вы хотели, чтобы goo свойство foo.moo было обновлено, установив для его свойства boo значение 'roo'. Затем он делает это. Однако когда он обновляет свойство, подобное этому, как и везде, он не изменяет исходные данные, а создает новый вывод, копируя свойства старого объекта, за исключением этого нового пути, который он устанавливает соответствующим образом. Ваш старый объект ('goo') имеет три свойства: {0: 'g'}, {1: 'o'} и {2: 'o'}, которые assocPath у Рамды (функция publi c также используется lensPath, которая выполняет эту работу) затем объединяется в один объект вместе с вашим {boo: 'roo'}.

Но я преувеличиваю здесь. Рамда никогда не делал такого выбора. Это просто то, что выпало из реализации. assocPath знает только два типа: массивы и объекты. Он знает, как реконструировать только эти типы. И действительно это работает как массивы и другие. Поскольку ваш foo.moo не является массивом, он обрабатывает его как объект.

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

Но я бы ожидал большого отскока.

Философия Рамды значительно отличается от философии Лоды sh. loda sh подчеркивает гибкость. Например, set позволяет записывать пути в виде массивов или строк с двумя примерами

_.set(object, 'a[0].b.c', 4);

_.set(object, ['x', '0', 'y', 'z'], 5);

, и многие функции имеют необязательные параметры. Он свободно изменяет данные, предоставленные ему. Он предназначен для «предоставления качественных утилитных методов как можно большему числу разработчиков с упором на согласованность, совместимость, настройку и производительность». как однажды сказал ее основатель 1045 *.

Рамда, напротив, гораздо меньше беспокоится о гибкости. Гораздо более важной целью для Рамды является простота . Его API не имеет дополнительных параметров. Когда он допускает несколько типов для аргумента, это происходит только потому, что они разделяют более высокую абстракцию. Путь к assocPath является массивом и только массивом; он обрабатывает объекты по сравнению с массивами, отмечая, является ли каждый элемент пути строкой или целым числом. И, конечно, Рамда никогда не изменяет ваши входные данные.

Рамда также не заинтересован в ручном удержании. Философия часто заключается в том, что мусор входит в мусор. И этот случай, кажется, граничит с этой территорией. Рамда охотно преобразует {moo: {goo: 'goo'}} в {moo: {goo: {boo: 'roo'}}}. Но вы должны сказать это, чтобы сделать это более явно: assoc(['moo', 'goo'], {boo: 'roo'}).

Так что запрос изменить это может быть трудным для продажи ... но это дружная толпа. Не стесняйтесь поднять это, если считаете это важным.

Мне кажется, что мне просто нужно импортировать функцию set из loda sh, чтобы предотвратить непредвиденное поведение.

Помните, однако, насколько отличается поведение. Самая большая разница в том, что loda sh изменяет свой ввод, чего Рамда не сделает. У них разные представления о том, какие ценности улучшать, а какие заменять (как в текущем примере.) Конечно, их подписи разные. Они по-разному относятся к индексам массивов. (Например, я не могу придумать, как в loda sh 'set добавить объект со строковым ключом' 0 '. И Рамда, конечно, не будет включать построенный Rectangle, когда вы называете что-то вроде assocPath(['grid', 'width'], newVal, myObj), тогда как loda sh с радостью мутирует внутренний объект Rectangle.)

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

...