我正在创建一个组件并试图破坏我的实现。这个想法是不允许用户操纵公开的属性。
实现是这样的:
function MyClass(){
var data = [];
Object.defineProperty(this, 'data', {
get: function(){ return data; },
set: function(){ throw new Error('This operation is not allowed'); },
configurable: false,
});
}
var obj = new MyClass();
try {
obj.data = [];
} catch(ex) {
console.log('mutation handled');
}
obj.data.push('Found a way to mutate');
console.log(obj.data)
如您所见,设置属性已处理,但用户仍然可以使用 .push
对其进行更改。这是因为我要返回一个引用。
我处理过这个案例:
function MyClass(){
var data = [];
Object.defineProperty(this, 'data', {
get: function(){ return data.slice(); },
set: function(){ throw new Error('This operation is not allowed'); },
configurable: false,
});
}
var obj = new MyClass();
try {
obj.data = [];
} catch(ex) {
console.log('mutation handled');
}
obj.data.push('Found a way to mutate');
console.log(obj.data)
如您所见,我返回一个新数组来解决这个问题。不确定它将如何影响性能。
问题:是否有其他方法不允许用户改变对象类型的属性?
我尝试过使用writable: false
,但是当我将它与get
一起使用时,它给了我错误。
注意:我希望该数组在类内可变,但不能从外部可变。
最佳答案
这里的问题是您有效地阻止了修改MyClass
的尝试。但是,MyClass
的其他对象成员仍然是 JavaScript 对象。你这样做的方式(每次调用 get
返回一个新的数组)是最好的方法之一,当然,这取决于你调用 get
的频率或者数组的长度可能会带来性能缺陷。
当然,如果您可以使用 ES6,您可以扩展原生 Array 来创建一个 ReadOnlyArray 类。实际上,您也可以在 ES5 中执行此操作,但您无法使用方括号从数组中的特定索引检索值。
如果您可以避免使用 Internet Explorer,另一个选择是使用代理
( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy )。
使用代理,您可以捕获调用以获取对象的属性,并决定返回什么或执行什么操作。
在下面的示例中,我们为数组创建一个代理。正如您在处理程序中看到的,我们定义了一个 get 函数。每当访问目标对象的属性值时都会调用此函数。这包括访问索引或方法,因为调用方法基本上就是检索属性(函数)的值,然后调用它。
如您所见,如果属性是整数,我们将返回数组中的该位置。如果属性是“length”,那么我们返回数组的长度。在任何其他情况下,我们都会返回一个 void 函数。
这样做的优点是 proxyArray 的行为仍然像一个数组。您可以使用方括号来获取其索引并使用属性长度。但是,如果您尝试执行诸如 proxyArray.push(23)
之类的操作,则什么也不会发生。
当然,在最终的解决方案中,您可能希望根据哪些内容来决定要做什么
方法正在被调用。您可能希望 map
、filter
等方法起作用。
最后,这种方法的最后一个优点是您保留对原始数组的引用,因此您仍然可以修改它并且可以通过代理访问它的值。
var handler = {
get: function(target, property, receiver) {
var regexp = /[\d]+/;
if (regexp.exec(property)) { // indexes:
return target[property];
}
if (property === 'length') {
return target.length;
}
if (typeof (target[property]) === 'function') {
// return a function that does nothing:
return function() {};
}
}
};
// this is the original array that we keep private
var array = [1, 2, 3];
// this is the 'visible' array:
var proxyArray = new Proxy(array, handler);
console.log(proxyArray[1]);
console.log(proxyArray.length);
console.log(proxyArray.push(32)); // does nothing
console.log(proxyArray[3]); // undefined
// but if we modify the old array:
array.push(23);
console.log(array);
// the proxy is modified
console.log(proxyArray[3]); // 32
当然,问题在于 proxyArray
并不是真正的数组,因此,根据您计划如何使用它,这可能是一个问题。
关于javascript - 禁用 JS 中的属性突变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49427270/