首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用javascript原型系统创建共享结构的不可变对象是否有意义?

使用javascript原型系统创建共享结构的不可变对象是否有意义?
EN

Stack Overflow用户
提问于 2015-11-07 15:57:17
回答 2查看 942关注 0票数 5

到目前为止,对于Javascript中的不变性,似乎有两种相反的解决方案:

  • immutable.js
  • 无缝不变

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

无缝不变使用的POJO是完全不可变的,没有任何魔力,但没有结构共享。

把这两个世界的优点结合起来就太好了。不可变的原型链/树是否是一个适当的解决方案?

基本的原型机制给了我们希望:

代码语言:javascript
复制
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)的突变(unshift)使其原型无法提供它们的值时,js引擎似乎会自动将这些值直接复制到实例中。我不知道,但这完全有道理。

但是,在处理不可变(键控/索引)对象时,很快会遇到问题:

代码语言:javascript
复制
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属性是从不可变的原型继承的,因此不可变。解决这个问题并不难:

代码语言:javascript
复制
var b = Object.create(a, {length: {value: a.length, writable: true}});

但可能还会有其他问题,特别是在更复杂、更真实的情况下。

也许有人已经处理过这个想法,并可以告诉我,是否值得对它进行推理。

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-11-07 16:50:57

js引擎似乎自动将这些值直接复制到实例中。

这是因为所有数组方法(shiftpush等)只使用对索引的赋值(幸运的是,对非数组没有自动更新的.length )。如您所知,赋值只是在继承对象上创建一个新属性,即使原型具有该属性(除非它具有奇怪的属性,如冻结长度示例中的那样)。

不管怎么说,你的实际问题是

不可变的原型链/树是否是一个适当的解决方案?

No..问题是,原型链从来不被垃圾收集。一旦所有继承的属性都被新的“变体”实例覆盖,引擎就不知道您“不需要”原型了--并且永远保留它。

您将需要手动垃圾收集(取消引用)它,这正是immutable.js与其结构共享所做的。只有那个mutating the [[prototype]] is a bad idea,所以您最好以其他方式管理您的结构,并手动进行属性查找。

票数 0
EN

Stack Overflow用户

发布于 2015-11-17 17:28:59

除了内存泄漏之外,当您使用原型系统进行结构共享时,还会遇到进一步的问题:

  • 长原型链中的不利查找时间
  • 在ES5中与数组相关的[[DefineOwnProperty]]丢失

哈希表中的查找通常非常有效。然而,如果一个对象经常发生变异,那么可能会产生很长的原型链。在最坏的情况下,整个链必须被遍历。如果这种行为是定期发生的,它可能会对性能产生不利影响。

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

代码语言:javascript
复制
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

opinionI确信,所有这些问题都可以解决,而且代码非常少,API很小,学习曲线也很浅。这样的系统可能不会像基于向量或哈希映射尝试的不可变数据结构那样有效。但是,它比仅仅复制对象要有效得多。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33584671

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档