我将以下内容作为模块的一部分(出于问题的目的简化了名称):
在“module.js”中:
var _arr;
_arr = [];
function ClassName () {
var props = {};
// ... other properties ...
props.arr = {
enumerable: true,
get: function () {
return _arr;
}
};
Object.defineProperties(this, props);
Object.seal(this);
};
ClassName.prototype.addArrValue = function addArrValue(value) {
// ... some code here to validate `value` ...
_arr.push(value);
}
在“其他文件.js”中:
var x = new ClassName();
通过上面的实现和下面的示例代码,可以通过两种方式向 arr
添加值。
// No thank you.
x.arr.push("newValue"); // x.arr = ["newValue"];
// Yes please!
x.addArrValue("newValue"); // Only this route is desired.
有谁知道如何实现只读数组属性?
注意:writeable
默认为 false,如果我明确设置它,则不会观察到任何差异。
最佳答案
Object.freeze()将按照您的要求进行操作(在正确实现规范的浏览器上)。在严格模式下尝试修改数组将无声地失败或抛出 TypeError
。
最简单的解决方案是返回一个新的卡住副本(卡住是破坏性的):
return Object.freeze(_arr.slice());
但是,如果预期读取多于写入,则延迟缓存最近访问的卡住副本并在写入时清除(因为 addArrValue
控制写入)
使用修改后的原始示例延迟缓存只读副本:
"use strict";
const mutable = [];
let cache;
function ClassName () {
const props = {};
// ... other properties ...
props.arr = {
enumerable: true,
get: function () {
return cache || (cache = Object.freeze(mutable.slice());
}
};
Object.defineProperties(this, props);
Object.seal(this);
};
ClassName.prototype.addArrValue = function addArrValue(value) {
// ... some code here to validate `value` ...
mutable.push(value);
cache = undefined;
}
使用 ES2015 类的延迟缓存只读副本:
class ClassName {
constructor() {
this.mutable = [];
this.cache = undefined;
Object.seal(this);
}
get arr() {
return this.cache || (this.cache = Object.freeze(this.mutable.slice());
}
function addArrValue(value) {
this.mutable.push(value);
this.cache = undefined;
}
}
“透明”可重用类 hack(很少需要):
class ReadOnlyArray extends Array {
constructor(mutable) {
// `this` is now a frozen mutable.slice() and NOT a ReadOnlyArray
return Object.freeze(mutable.slice());
}
}
const array1 = ['a', 'b', 'c'];
const array2 = new ReadOnlyArray(array1);
console.log(array1); // Array ["a", "b", "c"]
console.log(array2); // Array ["a", "b", "c"]
array1.push("d");
console.log(array1); // Array ["a", "b", "c", "d"]
console.log(array2); // Array ["a", "b", "c"]
//array2.push("e"); // throws
console.log(array2.constructor.name); // "Array"
console.log(Array.isArray(array2)); // true
console.log(array2 instanceof Array); // true
console.log(array2 instanceof ReadOnlyArray); // false
适当的可重用类:
class ReadOnlyArray extends Array {
constructor(mutable) {
super(0);
this.push(...mutable);
Object.freeze(this);
}
static get [Symbol.species]() { return Array; }
}
const array1 = ['a', 'b', 'c'];
const array2 = new ReadOnlyArray(array1);
console.log(array1); // Array ["a", "b", "c"]
console.log(array2); // Array ["a", "b", "c"]
array1.push("d");
console.log(array1); // Array ["a", "b", "c", "d"]
console.log(array2); // Array ["a", "b", "c"]
//array2.push("e"); // throws
console.log(array2.constructor.name); // "ReadOnlyArray"
console.log(Array.isArray(array2)); // true
console.log(array2 instanceof Array); // true
console.log(array2 instanceof ReadOnlyArray); // true
关于javascript - 如何使用 `defineProperty` 创建只读数组属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22515847/