2017-02-15 2 views
1

Я пытаюсь понять, как использовать Immutables в JavaScript/TypeScript, не тратя весь день на это. Я не совсем готов погрузиться в Immutable.js, потому что он, кажется, оставляет вас сухим и высоким, насколько это безопасно.Обновления и коллекции в JavaScript

Итак, давайте возьмем пример, где у меня есть массив, в котором все элементы имеют тип MyType. В моем классе у меня есть метод, который ищет массив и возвращает копию соответствующего элемента, поэтому мы не редактируем оригинал. Скажите теперь, что в более позднее время мне нужно посмотреть и посмотреть, находится ли объект в массиве, но у меня есть копия, а не оригинал.

Каков стандартный метод обработки этого? Любой метод, который я могу решить, чтобы определить, есть ли у меня этот элемент, будет принимать какую-то форму цикла через коллекцию и посещать каждый элемент, а затем выполнять неуклюжее совпадение равенства, независимо от того, превращает ли это их в строки или использует третий, партийной библиотеки.

Я хотел бы использовать Immutables, но я постоянно сталкиваюсь с такими ситуациями, которые делают их очень непривлекательными. Что мне не хватает?

+0

Вы не вернете копию объекта в своем массиве. Вы вернете объект. Если вам позже понадобилось изменить его, вместо этого вы сделаете копию с необходимыми изменениями. – SimpleJ

+0

Предполагая, что объект в массиве неизменен, зачем вы его копируете? – Bergi

+0

Тогда это ставит ответственность за код клиента за использование объекта, который он получил должным образом, что кажется неразумным. Это мой собственный проект, поэтому, конечно, это вариант, который у меня открыт, но в более крупном проекте с несколькими разработчиками это не кажется хорошей идеей. –

ответ

1

Я подозреваю, что мое решение не является «... стандартным методом обработки этого». Тем не менее, я думаю, что это по крайней мере a способ делать то, что, я думаю, вы просите.

Вы пишете, что у вас есть метод, который «... возвращает копию соответствующего элемента, поэтому мы не редактируем оригинал». Не могли бы вы изменить этот метод, чтобы вместо этого вернуть и оригинал и копию?

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

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

const retrieveDerivative = (array, elmtNum) => { 
 
    const orig = array[elmtNum]; 
 
    const clone = JSON.parse(JSON.stringify(orig)); 
 
    return {orig, clone}; 
 
}; 
 

 
const getIndexOfElmt = (array, derivativeOfElement) => { 
 
    return array.indexOf(derivativeOfElement.orig); 
 
}; 
 

 

 
const obj1 = {a: {b: 1}}; // Object #s are irrelevant. 
 
const obj3 = {a: {b: 1}}; // Note that all objects are identical 
 
const obj5 = {a: {b: 1}}; // by value and thus can only be 
 
const obj8 = {a: {b: 1}}; // differentiated by reference. 
 

 
const myArr = [obj3, obj5, obj1, obj8]; 
 

 
const derivedFromSomeElmt = retrieveDerivative(myArr, 2); 
 

 
const indexOfSomeElmt = getIndexOfElmt(myArr, derivedFromSomeElmt); 
 

 
console.log(indexOfSomeElmt);

+0

Как бы то ни было, любой объект может производить клон сам по запросу. Поэтому, если вы получаете объект, вы можете получить клон объекта, вызывая clone() на объекте. Я все еще пытаюсь написать эту статью без полчаса, потому что кажется, что где-то там вы должны нарисовать линию, где вы не будете полностью делать ее неизменной. И похоже, что существует много дополнительного кода вокруг неизменяемости - больше, чем код, который он должен устранить при защитном копировании и т. Д. –

1

Ситуация вы описали это один, где изменчивая структура данных имеет очевидные преимущества, но если вы в противном случае выгоды от использования immutables есть более эффективные подходы.

Сохраняя его неизменным, означает, что ваш новый обновленный объект совершенно новый, который разрезает оба пути: у вас может быть новый объект, но у вас также есть доступ к исходному объекту! Вы можете сделать много опрятных вещей с этим, например. объедините свои объекты, чтобы у вас была история отмены, и можете вернуться назад, чтобы отменить изменения.

Так что не используйте некоторые хакеры для поиска в массиве. Проблема с вашим примером заключается в том, что вы создаете новый объект в неподходящее время: не нужно возвращать функцию объекта. Попросите функцию вернуть исходный объект и вызовите обновление, используя исходный объект в качестве индекса.

let myThings = [new MyType(), new MyType(), new MyType()]; 

// We update by taking the thing, and replacing with a new one. 
// I'll keep the array immutable too 
function replaceThing(oldThing, newThing) { 
    const oldIndex = myThings.indexOf(oldThing); 
    myThings = myThings.slice(); 
    myThings[oldIndex] = newThing; 
    return myThings; 
} 

// then when I want to update it 
// Keep immutable by spreading 
const redThing = myThings.find(({ red }) => red); 
if (redThing) { 
    // In this example, there is a 'clone' method 
    replaceThing(redThing, Object.assign(redThing.clone(), { 
    newProperty: 'a new value in my immutable!', 
    }); 
} 

Все, что сказал, классы делают это намного сложнее. Гораздо проще сохранить простые объекты неизменяемыми, поскольку вы можете просто распространять старый объект на новый, например. { ...redThing, newProperty: 'a new value' }. Как только вы получите объект с более чем 1 высотой, вы можете найти immutable.js гораздо более полезным, так как вы можете mergeDeep.

+0

Да, я пытаюсь понять это, потому что Angular 2 сильно опирается на RxJS и не обнимает Immutables оставляет вас с видом мишмара, но мне сложно разрабатывать интуицию, где его использовать, и где не использовать его (и, похоже, он не использует его везде, все еще оставляет мишень). –

+0

Лично я бы предположил, что вы хотите, чтобы он был неизменным, если только что-то не является потенциальным _very_ большим (100MB + in-memory), или существует большая зависимость от модели данных (ваш - небольшой пример, но если у вас есть 'const user = {name: josh}; shopCartMap.set (пользователь, [{name: 'pants'}, количество: 1]); blogEntriesMap.set (пользователь, [{title: «Неизменность и вы»]); ', тогда вы есть много отношений для обновления, если пользователь неизменно меняется.) 'let' vs' const' также являются действительно хорошими индикаторами изменяемого/неизменяемого. Объект/массив, объявленный 'const', является изменяемым хранилищем данных, и' let' будет переназначен. –

Смежные вопросы