JS 相当于 Java 的 Collections.unmodifiableCollection

JS equivalent to Java's Collections.unmodifiableCollection

我经常对我的 java 代码使用这种策略,以便使一个集合只对外界可读,但要避免 big/often 克隆:

public abstract class MyClass {
    List<Long> myIds;

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

我想在我的 JS classes 中遵循相同的模式。这将使我的业务逻辑代码更加安全和清晰,因为我将能够控制在拥有这些字段的 class 中对我的列表(push/splice 等)的所有更改。

目前使用列表的 "private" 字段和从外部访问它们的 get-set 函数。唯一缺少的 link 相当于 java 的 Collections.unmodifiableCollection。不会复制整个列表的东西(例如 slice()),并且不会影响原始字段(例如 Object.freeze())。

JS有这样的功能吗?如果没有,有人怎么能达到类似的效果(自定义迭代器?)

如果你不限于只能使用JS解决方案,那么你可以尝试immutable.js(https://github.com/immutable-js/immutable-js).

来自文档:

Immutable.js provides many Persistent Immutable data structures including: List, Stack, Map, OrderedMap, Set, OrderedSet and 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

如果您不想复制对象,并且想确保原始对象不能在外部发生变异,一种选择是 return 一个代理,它会在任何尝试发生变异时抛出:

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 在技术上仍然可见 - 如果您想防止这种情况发生,您可以使用类似 的东西来确保私有数组真正只在 class.

但是代理有点慢。您可能会考虑使用 Typescript 的 ReadonlyArray 之类的东西 - 这样,您可以确保代码不包含任何在 returned 之后改变数组的内容,而使实际代码在运行时保持快速:

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