Javascript 保护闭包内的对象不被外部修改
我创建这个对象是为了能够在其中存储数据,它具有一定的保护级别。任何人都可以获得它,只要新数据通过验证,任何人都可以设置它Javascript 保护闭包内的对象不被外部修改,javascript,Javascript,我创建这个对象是为了能够在其中存储数据,它具有一定的保护级别。任何人都可以获得它,只要新数据通过验证,任何人都可以设置它 MF.factory = new function(){ var data = { SITE_URL: document.URL.replace(/(https?:\/\/.+?)\/.*/, '$1'), xhrSettings: { type: 'GET', error: functi
MF.factory = new function(){
var data = {
SITE_URL: document.URL.replace(/(https?:\/\/.+?)\/.*/, '$1'),
xhrSettings: {
type: 'GET',
error: function(){},
response: function(){},
max_upload_file_size: 8388608
}
}
this.get = function(key){
return data[key];
}
this.set = {
xhrSettings: {
type: function(type){if(type in {POST:0,GET:0,PUT:0}) data.xhrSettings.type = type;},
error: function(func){if(typeof func === 'function') data.xhrSettings.error = func;},
response: function(func){if(typeof func === 'function') data.xhrSettings.response = func;},
max_upload_file_size: function(size){if(!isNaN(size)) data.xhrSettings.max_upload_file_size = size;}
}
}
};
例如,现在我可以获取站点的URL
,但我无法设置它。这就是我想要的限制。我可以设置xhrSettings.type
,只要它是POST、GET或PUT
MF.factory.set.xhrSettings.type("DGD"); // No effect
MF.factory.set.xhrSettings.type("POST"); // data.xhrSettings.type = "POST"
但是如果我这样做
a = MF.factory.get('xhrSettings');
a.type = "DGD";
console.log(MF.factory.get('xhrSettings'));
我看到
data
中的对象发生了变化,这使得我的整个概念变得毫无用处。我如何解决这个问题?这正是的目的
来自MDN:
方法冻结一个对象:也就是说,阻止新的
不向其添加属性;防止现有属性被删除
被移除;并阻止现有属性或其
无法更改的可枚举性、可配置性或可写性。在里面
本质上,对象是有效地不可变的。该方法返回
被冻结的物体
注意:IE v8及以下版本不支持Object.freeze()
Object.freeze(objectName);
其中“objectName”是要冻结的对象的名称。我的建议是,与其返回对象,不如返回本身可以命名为可读性的属性:
type = MF.factory.get( 'xhrSettings.type');
type = "DGD";
console.log(MF.factory.get('xhrSettings.type'));
这意味着您的数据
对象具有平面属性:
var data = {
SITE_URL: document.URL.replace(/(https?:\/\/.+?)\/.*/, '$1'),
"xhrSettings.type": 'GET',
"xhrSettings.error": Function.prototype,
"xhrSettings.max_upload_file_size": 8388608
}
等等
而
set
变成了一个实际的函数
,它检查要设置的属性,并执行您想要的任何操作(返回和忽略、抛出错误等)我通过修改这个来解决它
this.get = function(key){
return (data[key] instanceof Object) ? Object.create(data[key]) : data[key];
}
一种解决方案是返回对象的副本
使用下划线/lodash,您可以使用.clone()
,因此:
this.get = function(key){
return _.clone(data[key]);
}
请记住,尽管那个克隆人只是做了一个肤浅的复制。因此,如果需要深入,可以为此滥用jqueryextend
,并添加数组检查:
this.get = function(key){
var x = data[key];
return typeof x !== 'object' ? x :
$.extend(true, (Array.isArray(x) ? [] : {}), x);
}
第二种解决方案仍然不是完美的,因为它不会处理循环对象,克隆getter/setter等可能会有问题。但对于简单的情况,即使是第一种解决方案也可以。@Andy-是的,谢谢你指出。我会将其添加到答案中。但即使使用我的set
函数,也不会使对象不可更改吗?该函数本应更改对象,但会首先验证传入的数据?它在文档中,但有时人们不会深入页面;)@php_nub_qq-是的,它将使对象完全不可变。@php_nub_qq-a)重新构造应用程序,以便将对象的冻结副本传递给读卡器作用域-或者-b)不要在名称空间之外公开setter,只返回getter作为对象方法的一部分。MF.factory.get('xhrSettings.type')
为我返回未定义的
:/嗯,是的,你必须更改你的代码。您的数据
对象需要具有原始属性。我更新了答案来说明这一点。这是一个好主意,但我需要能够从数据中返回整个对象,以便扩展其他对象并填充,然后在get
中克隆对象。不过,此代码不适用于数组<代码>data.props=[1,2,3];x、 获得(‘道具);//[undefined,undefined,undefined]
@c69它确实适合我。它返回一个对象而不是数组,但是键值对是相同的,所以我认为这不是问题,除非你想使用数组。prototype
,在这种情况下,我需要进一步调整它