4

到目前为止共享结构不变的对象,也似乎是不可改变的两个对立的解决方案,在Javascript:是否有意义创建利用JavaScript的原型系统

  • immutable.js
  • 无缝不变

immutable.js引入了与对象和数组的默认javascript协议不兼容的自己(浅)不可变对象。

seamless-immutable使用完全不变的POJO,没有任何魔法,但没有结构共享。

将两个世界的最好结合起来会很棒。难道不可变的原型链/树会是一个合适的解决方案吗?

的基本原型机制带来了希望:

var a = [1, 2, 3]; 
var b = Object.create(a); 

b[0]; // 1 
b.map(function (x) { return ++x; }); // 2, 3, 4 

b.push(4, 5, 6); // initial assignment of b 
a; // 1, 2, 3 
b; // 1, 2, 3, 4, 5, 6 

for (var i = 0; i < b.length; i++) { 
    console.log(b[i]); 
} // 1, 2, 3, 4, 5, 6 

a[1] = null; // prototype mutation 
a; // 1, null, 3 
b; // 1, null, 3, 4, 5, 6 

b.unshift(0); // instance mutation 
a; // 1, null, 3 
b; // 0, 1, null, 3, 4, 5, 6 !!! 

每当当前实例(B)的突变(不印字)使得它不可能为它的原型来提供他们的价值观,JS引擎似乎复制这些值自动直接进入实例。我不知道,但它总是有意义的。

然而,不可变的工作(键/索引)对象一个快速遇到的问题:

var a = [1, 2, 3]; 
Object.freeze(a); 
var b = Object.create(a); 
b.push(4, 5, 6); // Error: Cannot assign to read only property "length" 
Object.freeze(b); 

这一个是简单的:length属性从不可改变原型继承,并因此不可变。解决问题并不难:

var b = Object.create(a, {length: {value: a.length, writable: true}}); 

但是可能会有其他问题,特别是在更复杂的现实世界的情况下。

也许有人已经处理了这个想法,可以告诉我,如果值得推理的话。

Aadit的answer相关的问题和Bergi的评论触及我的问题,没有给出答案。

+0

我觉得这会让一个**真的有趣的讨论,但不是正确的Stack Overflow讨论更具体的问题)。一旦你打到20代表,你应该完全来和我们在[聊天](https://chat.stackoverflow.com/rooms/17/javascript)讨论。 –

+0

是的,我不想在那边与Aadit进行讨论,但我很乐意在这里提供答案。并希望@AaditMShah可以提供一些对应点,我想学习一些新的:-) – Bergi

回答

0

JS引擎似乎这些值直接复制到实例自动

这是因为所有的阵列方法(shiftpush等),只需使用分配给指数(幸运的是,到.length,这不会在非数组上自动更新)。如你所知,赋值只是在继承对象上创建一个新属性,即使原型具有该属性(除非它具有奇怪的属性,就像在你的冻结长度范例中一样)。

无论如何,您的实际问题是

能一成不变的原型链/树是一个妥善的解决办法?

。问题在于原型链永远不会被垃圾收集。一旦所有继承的属性被新的“突变”实例覆盖,引擎不会再知道你“不需要”原型,并且永远保持它。
您需要手动垃圾收集(取消引用)它,这正是immutable.js与其结构共享所做的一样。只有那mutating the [[prototype]] is a bad idea,所以你最好用其他方式管理你的结构,并手动进行属性查找。

+0

当我提到原型树时,我提到了共享原型的想法。这在原型上实际上是误导和笨拙的。当然,每个javascript对象只能有一个直接的原型。感谢您的澄清! – rand

+0

@IvenMarquardt:啊,我明白了。只是有其他的语言确实允许多个原型继承并更容易地交换出来,所以我想确保你不会被这些原型弄糊涂。 – Bergi

+0

是的,'[[prototype]]'不是一个选项。我想你不能防止内存泄漏,至少不能在这个低级别上。 – rand

0

除了内存泄漏遇到更多的问题,当您使用结构共享原型系统:

  • 不利查找时间长的原型链
  • 在使用数组 连接 [[DefineOwnProperty]] ES5损失

查找散列表通常非常有效。如果一个对象经常发生变异,然而,可能会出现非常长的原型链。在最坏的情况下,整个链条必须被遍历。如果此类行为定期发生,可能会对性能产生不利影响。

数组子类导致[[DefineOwnProperty]]丢失。这个内部方法是负责与元素的数组中的实际数量同步length属性:

function A() {} 
A.prototype = Array.prototype; 
var a = new A(); 

a[0] = 0, a[1] = 1; 
console.log(a.length); // 0 
a.length = 2; 
console.log(a); // [0, 1] 
a.length = 1; 
console.log(a[1]); // 1 

[观点]我相信,所有这些问题都可以解决,并且有令人难以置信的少的代码,一个微小的API和一个浅显的学习曲线。这样的系统可能不会像基于向量或哈希映射尝试的不可变数据结构那样高效。但它会比单纯的复制对象更有效率。[/ views]

相关问题