2

我经常在我的 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中有这样的功能吗?如果没有,有人怎么能达到类似的效果(自定义迭代?)

4

2 回答 2

3

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

从文档:

Immutable.js 提供了许多 Persistent Immutable 数据结构,包括:List、Stack、Map、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

于 2019-05-27T09:04:48.707 回答
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在技术上仍然是可见的——如果你想阻止这种情况,你可以使用Wea​​kMap之类的东西来确保私有数组真正只在类内部可见。

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

private myIds = ['foo', 'bar']
public getIds() {
  return this.myIds as ReadonlyArray<string>;
}
于 2019-05-27T09:05:12.123 回答