JS相当于Java的Collections.unmodifiableCollection

时间:2019-05-27 08:54:16

标签: javascript readonly-collection

我经常在Java代码中使用此策略,以使Collection仅对外界可读,但避免大的/经常的克隆:

public abstract class MyClass {
    List<Long> myIds;

    public Collection<Long> getIds() {
        return Collections.unmodifiableCollection(this.myIds);
    }
}

我想在我的JS类中遵循相同的模式。这将使我的业务逻辑代码更加安全和整洁,因为我可以控制对拥有该字段的类中的列表(推送/拼接等)进行的所有更改。

目前,将“私有”字段用于列表,并使用get-set函数从外部访问它们。唯一缺少的链接与Java的Collections.unmodifiableCollection等效。不会复制整个列表的东西(例如slice()),并且不会影响原始字段(例如Object.freeze())。

JS中是否有这样的功能?如果没有,那么别人怎么能达到类似的效果(自定义可迭代对象?)

2 个答案:

答案 0 :(得分:3)

如果您不仅限于使用JS解决方案,则可以尝试 immutable.js https://github.com/immutable-js/immutable-js)。

从文档中

  

Immutable.js提供了许多持久不变的数据结构,包括:列表,堆栈,地图,OrderedMap,Set,OrderedSet和Record

这是带有 Immutable.List 的简单示例:

const list1 = Immutable.List([ 1, 2 ]);
const list2 = list1.push(3, 4, 5);
const list3 = list2.unshift(0);
const list4 = list1.concat(list2, list3);

console.log('list1:', list1); // [1,2]
console.log('list2:', list2); // [1,2,3,4,5]
console.log('list3:', list3); // [0,1,2,3,4,5]
console.log('list4:', list4); // [1,2,1,2,3,4,5,0,1,2,3,4,5]
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.js"></script>

于2019年5月27日星期一09:55:43 GMT更新

答案 1 :(得分:3)

如果您不想复制对象,并且要确保不能从外部对原始对象进行突变,则一种选择是返回一个代理,当任何尝试进行突变的情况下抛出该代理:

const handler = {
  get(obj, prop) {
    return obj[prop];
  },
  set() {
    throw new Error('Setting not permitted');
  }
}
class MyClass {
  _myIds = ['foo', 'bar']
  getIds() {
    return new Proxy(this._myIds, handler);
  }
}

const instance = new MyClass();
const ids = instance.getIds();
console.log(ids);
// Error:
// ids[2] = 'baz';
// Error:
// ids.push('baz');

当然,instance._myIds在技术上仍然是可见的-如果要防止这种情况,可以使用类似WeakMap的名称来确保私有数组仅在类内部才真正可见。 / p>

但是代理有点慢。您可能会考虑使用类似Typescript的ReadonlyArray的方法-这样,您可以确保代码不包含返回后使数组变异的任何内容,同时保持实际代码在运行时的速度快:

private myIds = ['foo', 'bar']
public getIds() {
  return this.myIds as ReadonlyArray<string>;
}