如何在Javascript中使用共享的、不可变的引用类型来跟踪更改
How to track changes with shared, immutable reference types in Javascript
考虑以下示例:
function add(x, y) { return x + y; }
var collection = Object.freeze([1, 2, 3, 4]);
var consumerA = collection; // expects steady data
var consumerB = collection; // requires the latest data
var updatedCollection = collection.concat(5);
consumerA.reduce(add, 0); // 10 (desired result)
consumerB.reduce(add, 0); // 10 (incorrect result, should be 15)
consumerA
使用它所期望的不可变数据进行操作。在Javascript中可以做些什么来确保consumerB
始终访问最新的数据?
请注意:仅仅深度复制consumerA
并将collection
视为可变数据是不可行的。
UPDATE:该示例仅用于说明由共享引用类型引起的根本问题:一些使用者(或引用持有者)依赖于不可变的数据,另一些则依赖于可变的数据。我正在寻找一种适当的更改跟踪机制,在不破坏不可变数据的好处的情况下解决这个问题。
也许"变化跟踪"这个词太模糊了。关于变化跟踪,我指的是consumerB
被告知变化(推动机制)或(更有趣的)能够发现变化(拉动机制)的一种方式。后者将要求consumerB
以某种方式访问更新的集合。
在声明collection
时使用Object.freeze
,因此不能向collection
添加属性。
创建consumerB
时,执行对象collection
的副本
var consumerB = collection;
因此,不能像collection
那样向consumerB
添加属性。
你需要克隆对象而不是复制它。你可以这样做:
var consumerB = JSON.parse(JSON.stringify(collection));
好吧,这是我唯一的解决方案,但可能还有其他解决方案。我将我的不可变集合封装在一个可变对象中。需要常量数据的使用者拥有对集合本身的引用。需要当前状态的使用者持有对包装器的引用。为了避免克隆,我使用了一种原始形式的结构共享:
function add(x, y) { return x + y; }
var collection = Object.freeze([1, 2, 3, 4]);
var atom = {state: collection};
var consumerA = collection;
var consumerB = atom;
console.log(consumerA === consumerB.state); // true (obviously)
// naive structural sharing to avoid cloning
atom.state = Object.create(atom.state, {length: {value: atom.state.length, writable: true}});
atom.state.push(5);
Object.freeze(atom.state);
// as desired
console.log(consumerA.reduce(add, 0)); // 10
console.log(consumerB.state.reduce(add, 0)); // 15
// structural sharing is used
console.log(Object.getPrototypeOf(consumerB.state) === collection); // true
// object comparison simply by reference check
console.log(consumerA === consumerB.state); // false
通过将不可变集合包装在可变包装器中,它就成为了一种持久数据类型。这意味着它可以被视为一个普通的、可变的对象,但保留其以前的版本,因此是持久的。顺便说一句,将包装器命名为atom
并不是偶然的,而是对Clojure中相应数据类型的引用。
请注意:使用原型系统进行结构共享可能会导致内存泄漏,应谨慎使用。
- 如何将不可变的js导入angular 2(alpha)
- JavaScript Array unshift() 以一种不可变的方式
- 将对象从另一个不可变的Map分配给Map是否意味着深度克隆
- 在Javascript中调用对象方法时不是函数类型错误
- 可以“;超级“;可以在子类的方法内部使用,在不直接引用的情况下调用相应的超类方法
- 函数在不可变的js和redux存储中
- 如何在JS中创建对象的可变和不可变副本
- 如何创建以下数组的克隆而不是引用
- 使用动态键返回不可变状态
- 不可变的JS映射或列表
- Node js:如何获取文件签名标头而不是 mime 类型
- POST to Django 模型与 ManyToManyFiled 给出不正确的类型.预期 pk 值,
- 如何使用不可变表示此数组重新排序示例
- 为什么像这样向 JavaScript 引用类型添加方法不起作用
- 如何在Javascript中使用共享的、不可变的引用类型来跟踪更改
- EXT JS 5:为什么我不能获得引用类型的模型对象
- javascript中的不可变类型
- 不可变基本类型
- 我如何使用facebook/immutable-js自定义不可变类型
- 如何为不可变js类型写一个流类型定义