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>;
}
我经常对我的 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
在技术上仍然可见 - 如果您想防止这种情况发生,您可以使用类似
但是代理有点慢。您可能会考虑使用 Typescript 的 ReadonlyArray
之类的东西 - 这样,您可以确保代码不包含任何在 returned 之后改变数组的内容,而使实际代码在运行时保持快速:
private myIds = ['foo', 'bar']
public getIds() {
return this.myIds as ReadonlyArray<string>;
}