Immutable.js关系 [英] Immutable.js relationships

查看:72
本文介绍了Immutable.js关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想象一下这样一种情况,约翰有两个孩子爱丽丝和鲍勃,而鲍勃有一只猫猎户座.

var Immutable = require('immutable');

var parent = Immutable.Map({name: 'John'});
var childrens = Immutable.List([
    Immutable.Map({name: 'Alice', parent: parent}),
    Immutable.Map({name: 'Bob', parent: parent})
]);
var cat = Immutable.Map({name: 'Orion', owner: childrens.get(1)});

几年后,约翰想重命名为简.

var renamedParent = parent.set('name', 'Jane');

...让孩子们知道.

childrens = childrens.map(function(children) {
    children.set('parent', renamedParent);
});

然后我必须更新猫,因为鲍勃变了.

cat = cat.set('owner', childrens.get(1));

当一个对象更改时,是否可以自动更新所有相关对象?我看了光标,但是我不确定它们是否是一个解决方案.如果可以的话,您能举个例子吗?

解决方案

将问题解释为:

当一个不可变集合中的一个对象发生更改时,是否可以自动更新所有相关对象?

简短回答

否.

长答案

不,但是不变的数据结构没有任何变化,所以这不是问题.

更长的答案

它更复杂...

不可移植性

不可变对象的全部要点是,如果您引用了一个不可变对象,则无需费心检查其任何属性是否已更改.那么,这不是问题吗?好吧...

后果

有一些后果-好坏取决于您的期望

但是世界是可变的

当然,在实践中,我们经常会处理随时间变化的价值观.似乎不变的状态无法描述可变的世界,但是人们有一些处理它的方法.

以这种方式查看:如果您在某个ID上有住所,而您又移动到另一个地址,则应更改该ID以使其与新的真实数据保持一致,因为您居住在该地址不再是真实的.但是,当您在购买包含地址的商品时收到发票,然后更改地址时,发票将保持不变,因为在写发票时您住在该地址仍然是真实的.现实世界中的某些数据表示是不可变的,例如该示例中的发票,而另一些则是可变的,例如ID.

现在以您的示例为例,如果您选择使用不可变的结构为数据建模,则必须以一种考虑我示例中的发票的方式来考虑它.可能确实是数据不是最新的,但在某些时间点它始终是一致且正确的,并且永远不会改变.

如何应对变化

那么如何用不变的数据来建模变化呢?在 Clojure 中,有一种很好的方法是使用参考代理商 ClojureScript (针对JavaScript的Clojure编译器)支持其中的某些功能(特别是Atom应该像Clojure一样工作但没有参考,STM,Var或代理-请参阅什么是ClojureScript和Clojure在并发功能方面的差异).

查看如何在ClojureScript中实现原子,看来您可以只需使用普通的JavaScript对象即可实现相同效果.它可以用于具有可变对象的JavaScript对象,但是它具有引用不可变对象的属性-您将无法更改该不可变对象的任何属性,但可以构造一个不同的不可变对象,然后将顶级可变对象中的旧对象交换为新对象.

Haskell .org/wiki/Purely_functional"rel =" noreferrer>纯功能可能有不同的方式来应对可变的世界,例如单子(众所周知,这个概念很难解释- JavaScript:好零件 发现者JSON 将其归因于他的演讲单子和性腺).

您的问题似乎很简单,但它涉及的问题实际上却非常复杂.当然,对于一个问题是否可以自动更新所有相关的对象,只是回答否",可能会失去要点,但这要复杂得多,并且说在不可变的对象中,任何事物都不会改变(因此这个问题永远不会发生)将同样无济于事.

可能的解决方案

您可以有一个顶层对象或变量,您可以始终从中访问所有结构.假设您有:

var data = { value: Immutable.Map({...}) }

如果您始终使用data.value(或使用一些更好的名称)访问数据,则可以将data传递给代码的其他部分,并且只要状态更改,您就可以分配一个新的Immutable.Map. ({...})到您的data.value,到那时,所有使用data的代码都将获得新的值.

如何以及何时将data.value更新为新的不可变结构,可以通过使它自动由用于更新状态的setter函数触发来解决.

另一种方法是在每种结构的级别上使用类似的技巧,例如-我使用变量的原始拼写:

var parent = {data: Immutable.Map({name: 'John'}) };
var childrens = {data: Immutable.List([
    Immutable.Map({name: 'Alice', parent: parent}),
    Immutable.Map({name: 'Bob', parent: parent})
])};

但是您必须记住,值所具有的不是不变结构,而是那些引用了引入了附加间接性的不变结构的附加对象.

一些阅读

我建议看一下其中一些项目和文章:

    Peter Hausel的
  • 不可变的反应文章
  • Morearty.js -在反应光标-与Facebook一起使用的功能状态管理抽象
  • Omniscient -一个为React组件提供抽象的库,可以快速进行自上而下的渲染拥抱不变的数据 * Om -React的ClojureScript接口
  • mori -用于在JavaScript中使用ClojureScript持久数据结构的库
  • Fluxy -Facebook Flux体系结构的实现
  • Facebook的不可变-JavaScript的持久性数据集合,当与 Facebook Flux 面临着您遇到的类似问题(寻找如何将Immutable与React和Flux结合使用可能会给您一些好主意)

我希望即使没有给出简单的解决方案,该答案也将有所帮助,因为用不可变的结构描述可变的世界是一个非常有趣且重要的问题.

其他方法

对于不可变性的另一种处理方法,即不可变对象是不一定是恒定数据的代理,请参见 Immutable Yegor Bugayenko及其文章的对象与常识" 网络研讨会:

Yegor Bugayenko使用不可变"一词的含义与在函数式编程中通常所指的含义略有不同.他提倡使用术语的原始含义,而不是使用不变或持久的数据结构和函数式编程,这样您就不会真正改变任何对象,而是可以要求它更改某些状态或改变某些对象,从而倡导使用面向对象的编程.数据,它本身被认为是与对象分离的.容易想象一个与关系数据库对话的不可变对象.对象本身可以是不可变的,但是它仍然可以更新存储在数据库中的数据.很难想象可以将存储在RAM中的某些数据与对象与数据库中的数据同等地分开,但是实际上并没有太大的区别.如果您将对象看作是暴露某些行为的自治实体,并且尊重它们的抽象边界,那么将对象视为不同于数据的东西实际上是很有意义的,那么您就可以拥有具有可变数据的不可变对象.

如果需要任何澄清,请发表评论.

Imagine a situation that John have two childrens Alice and Bob, and Bob have a cat Orion.

var Immutable = require('immutable');

var parent = Immutable.Map({name: 'John'});
var childrens = Immutable.List([
    Immutable.Map({name: 'Alice', parent: parent}),
    Immutable.Map({name: 'Bob', parent: parent})
]);
var cat = Immutable.Map({name: 'Orion', owner: childrens.get(1)});

After few years John wants to rename to Jane.

var renamedParent = parent.set('name', 'Jane');

...and let childrens know about it.

childrens = childrens.map(function(children) {
    children.set('parent', renamedParent);
});

Then I have to update cat because Bob changed.

cat = cat.set('owner', childrens.get(1));

Is it possible to automatically update all related objects when one object change? I looked at Cursors, but I'm not sure if they are a solution. If it possible, can you give me an example?

解决方案

Paraphrasing the question:

Is it possible to automatically update all related objects when one object changes in an immutable collection?

Short answer

No.

Long answer

No, but nothing ever changes in an immutable data structure so that's not a problem.

Even longer answer

It's more complicated...

Immutability

The whole point of immutable objects is that if you have a reference to an immutable object you don't ever have to bother checking whether any of its properties have changed. So, is it a non-issue? Well...

Consequences

There are some consequences of that - whether they are good or bad depends on your expectations:

  • There is no difference between pass-by-value and pass-by-reference semantics
  • Some comparisons can be easier
  • When you pass a reference to an object somewhere you don't have to worry that some other part of code will change it
  • When you get a reference to an object from somewhere you know it will never change
  • You avoid some problems with concurrency because there is no notion of a change in time
  • When nothing ever changes you don't have to worry whether changes are atomic
  • It's easier to implement software transactional memory (STM) with immutable data structures

But the world is mutable

Of course in practice we often deal with values that change in time. It may seem that immutable state can't describe mutable world but there are some ways people deal with it.

Look at it this way: if you have your address on some ID and you move to a different address, that ID should be changed to be consistent with new true data, because it is no longer true that you live at that address. But when you get an invoice when you buy something which contains your address and then you change your address, the invoice stays the same because it is still true that you lived at that address when the invoice was written. Some data representations in the real world are immutable, like invoices in that example, and some are mutable like IDs.

Now taking your example, if you choose to use immutable structures to model your data, you have to think about it in a way that you think about the invoice from my example. It may be true that the data is not up to date but it will always be consistent and true for some point in time, and it will never change.

How to deal with change

So how to model change with immutable data? There is a nice way it has been solved in Clojure using Vars, Refs, Atoms, and Agents, and ClojureScript (a compiler for Clojure that targets JavaScript) supports some of them (in particular Atoms are supposed to work as in Clojure but there are no Refs, STM, Vars or Agents - see what are the differences between ClojureScript and Clojure regarding concurrency features).

Looking at how Atoms are implemented in ClojureScript it seems that you can just use ordinary JavaScript objects to achieve the same. It will work for things like having a JavaScript object that is itself mutable, but it has a property that is a reference to an immutable object - you will not be able to change any properties of that immutable object, but you will be able to construct a different immutable object, and swap the old one to the new one in your top-level mutable object.

Other languages like Haskell that are purely functional may have different ways to deal with mutable world, like monads (a concept notoriously hard to explain - Douglas Crockford, author of JavaScript: The Good Parts and discoverer of JSON attributes it to "the monadic curse" in his talk Monads and Gonads).

Your question seems simple but the problem it touches is actually quite complicated. Of course it would be missing the point to just answer "No" to your question whether it is possible to automatically update all related objects when one object changes, but it is more complicated than that, and saying that in immutable objects nothing ever changes (so this problem never happens) will be equally unhelpful.

Possible solutions

You can have a top level object or variable from which you always access all your structures. Let's say you have:

var data = { value: Immutable.Map({...}) }

If you always access your data using data.value (or with some better names) then you can pass the data to some other part of your code, and whenever your state changes you can just assign a new Immutable.Map({...}) to your data.value and at that point all your code that uses data will get fresh values.

How and when to update the data.value to a new immutable structure could be solved by making it automatically triggered from your setter functions that you would use to update your state.

Another way would be to use similar tricks at the level of every structure, for example - I use the original spelling of the variables:

var parent = {data: Immutable.Map({name: 'John'}) };
var childrens = {data: Immutable.List([
    Immutable.Map({name: 'Alice', parent: parent}),
    Immutable.Map({name: 'Bob', parent: parent})
])};

but then you have to remember that what you have as values are not immutable structures but rather those additional objects with references to immutable structures that introduce an additional level of indirection.

Some reading

What I would suggest is to look at some of those projects and articles:

  • Immutable React article by Peter Hausel
  • Morearty.js - using immutable state in React like in Om but written in pure JavaScript
  • react-cursor - functional state management abstraction for use with Facebook
  • Omniscient - a library providing an abstraction for React components that allows for fast top-down rendering embracing immutable data * Om - ClojureScript interface to React
  • mori - a library for using ClojureScript's persistent data structures in JavaScript
  • Fluxy - an implementation of Facebook's Flux archtecture
  • Facebook's Immutable - persistent data collections for JavaScript that when combined with Facebook React and Facebook Flux faces similar problems that you have (searching for how to combine Immutable with React and Flux may give you some good ideas)

I hope this answer even if not giving a simple solution will nevertheless be helpful, because describing mutable world with immutable structures is a very interesting and important problem.

Other approaches

For a different approach to immutability, with immutable objects that are proxies to data that is not necessarily constant, see the Immutable Objects vs. Common Sense webinar by Yegor Bugayenko and his articles:

Yegor Bugayenko uses the term "immutable" in a slightly different sense than what it usually means in the context of functional programming. Instead of using immutable or persistent data structures and functional programming, he advocates the use of object oriented programming in the original sense of the term in a way that you never actually mutate any object but you can ask it to change some state, or mutate some data, that is itself considered to be separate from the object. It's easy to imagine an immutable object that talks to a relational database. The object itself can be immutable but it can still update the data stored in the database. It's somewhat harder to imagine that some data stored in RAM can be thought of as equally separate from the object as the data in the database but there is really not much difference. If you think about objects as autonomous entities that expose some behavior and you respect their abstraction boundaries then it actually makes a lot of sense to think about objects as something different than just data and then you can have immutable objects with mutable data.

Please comment if anything needs some clarification.

这篇关于Immutable.js关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆