我经常在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中是否有这样的功能?如果没有,那么别人怎么能达到类似的效果(自定义可迭代对象?)
答案 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>;
}