保护封闭内的物体不被外部修改

时间:2014-07-31 14:55:51

标签: javascript

我创建了这个对象,以便能够在其中存储具有一定程度保护的数据。任何人都可以得到它,任何人都可以设置它,只要新数据通过验证。

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;}
        }
    }
};

例如,现在我可以获得SITE_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内的对象发生了变化,这使我的整个概念变得毫无用处。我该如何解决这个问题?

5 个答案:

答案 0 :(得分:1)

这正是 Object.freeze() 的用途。

来自MDN:

  

Object.freeze()方法冻结一个对象:即阻止new   属性被添加到它;防止现有属性   被删除;并防止现有的属性,或他们的   可更改性,可配置性或可写性。在   本质上,对象是有效不可变的。该方法返回   被冻结的物体。

注意:IE v8及更低版本不支持Object.freeze()。

答案 1 :(得分:1)

我的建议不是返回对象,而是返回属性本身可以命名为可读性的属性:

  type = MF.factory.get( 'xhrSettings.type');
  type = "DGD";
  console.log(MF.factory.get('xhrSettings.type'));

这意味着您的data对象具有平面属性:

var data = {
    SITE_URL: document.URL.replace(/(https?:\/\/.+?)\/.*/, '$1'),
    "xhrSettings.type": 'GET',
    "xhrSettings.error": Function.prototype,
    "xhrSettings.max_upload_file_size": 8388608
}

并且set成为一个实际的function,用于检查尝试设置哪个属性并执行您想要的任何操作(返回并忽略,抛出错误等)

答案 2 :(得分:0)

Object.freeze(objectName);

其中“objectName”是您要冻结的对象的名称。

答案 3 :(得分:0)

我通过将this.get修改为以下

解决了这个问题
this.get = function(key){
    return (data[key] instanceof Object) ? Object.create(data[key]) : data[key];
}

答案 4 :(得分:0)

一种解决方案是返回对象的副本。

使用下划线/ lodash,您可以使用_.clone(),所以:

this.get = function(key){
    return _.clone(data[key]);
}

请记住,尽管该克隆只执行浅拷贝。所以,如果你需要它,你可以滥用jquery extend,并添加数组检查:

this.get = function(key){
    var x = data[key];
    return typeof x !== 'object' ? x :
        $.extend(true, (Array.isArray(x) ? [] : {}), x);
}

这第二个解决方案仍然不完美,因为它不会处理圆形对象,并且可能存在克隆getter / setter等问题。但对于简单的情况,即使第一个解决方案也没问题。