我有以下JavaScript Object Literal Notiation对象
var Parameters= {
modal_window:{
backdrop:true,
keyboard:true,
show:true,
remote:false,
type:{
normal:function(){
this.footer.button.accept.type='btn btn-primary';
this.header.type='modal-header';
},
success:function(){
this.footer.button.accept.type='btn btn-success';
this.header.type='modal-header alert alert-success';
},
info:function(){
this.footer.button.accept.type='btn btn-info';
this.header.type='modal-header alert alert-info';
},
error:function(){
this.footer.button.accept.type='btn btn-danger';
this.header.type='modal-header alert alert-error';
},
warning:function(){
this.footer.button.accept.type='btn btn-warning';
this.header.type='modal-header alert';
}
}
},
header:{
title:undefined,
type:this.window.type.normal.header
},
footer:{
button:
{
accept:{
title:'Accept',
click:undefined,
type:undefined
},
cancel:{
title:'Cancel',
click:undefined
}
}
}
};
是否可以使header.type和footer.button.accept.type只读变量,只能通过window.type.normal,window.type.success等进行更改?
澄清: 我想在这里作一些澄清。我的Parameters.header.type 应该是只读的,并且应该具有默认值。而当用户 选择例如Parameters.modal_window.type.normal 必须更改Parameters.header.type。
答案 0 :(得分:4)
尽管每个人都说,但您可以在支持Object.defineProperty
的现代浏览器中创建只读属性。
var obj = {};
Object.defineProperty(obj, 'someProp', {
configurable: false,
writable: false,
value: 'initial value'
});
obj.someProp = 'some other value';
console.log(obj.someProp); //initial value
修改强>
再次阅读你的问题之后,我明白你的意思是真正的私人成员或私人变量。这可以通过使用闭包和定制的getter / setter来实现。
注意:为了示例,我简化了对象的结构。
var Parameters = (function () {
var headerType = 'some value'; //private variable
return {
modal_window: {
type: {
normal: function () {
//custom logic
headerType = 'some new value'; //set private variable
}
}
},
header: {
get type() { return headerType; } //define a getter only
//for older browsers, you could just define a normal function
//which you would have to access like Parameters.header.type()
//type: function () { return headerType; }
}
};
})();
var header = Parameters.header;
console.log(header.type); //some value
header.type = 'some other val';
console.log(header.type); //some value
Parameters.modal_window.type.normal();
console.log(header.type); //some new value
既然我们知道可以强制实施真正的隐私,我不确定它是否真的值得。实施真正的隐私会使设计复杂化并降低可测试性(取决于具体情况)。一种非常流行的方法是使用命名约定(例如_myPrivateVar
)简单地识别私有成员。这清楚地表明了这一点,并告诉程序员他们应该像私人一样对待那个成员。
答案 1 :(得分:2)
你可以让它们成为这样的功能:
header:{
title:undefined,
type: function(){
return Parameters.modal_window.type.normal.header;
}
}
答案 2 :(得分:2)
如果您需要支持IE 8或更早版本,您可以创建一个访问器方法来检索该值,然后使用私有变量来存储实际数据。如果您正确定义了方法,则可以从中设置私有变量,但不能由外部世界设置。在IE8中,没有能力定义只读属性,因此您必须使用访问器。
请参阅Crockford关于私人会员数据的论文:http://javascript.crockford.com/private.html,详细了解如何设置您的访问者可以作为其接口的私人数据。
如果您愿意要求IE9或更高版本,那么您可以通过Object.defineProperty()
使用getter和闭包中的私有变量。如果没有setter,则无法从外部设置它,但是在闭包内定义的方法(在Crockford的文章中描述)仍然可以设置私有变量的值。您将拥有一个只读属性,也可以通过一些自己的方法设置。
答案 3 :(得分:2)
您可以创建property并将其设置为不可写。您的构造函数必须使用属性替换值。如果属性返回的变量是在闭包中捕获的,而不是暴露给其他任何东西,那么它将与只读一样好。如果没有更改,您甚至不需要关闭,只需使用value
配置选项。
编辑:根据您的要求,
var Properties = function(obj) {
var makePropRecursive = function(prop) {
var old_prop = obj[prop];
delete obj[prop];
var prop_obj = {};
for (var attr in old_prop) {
if (old_prop.hasOwnProperty(attr)) {
Object.defineProperty(prop_obj, attr, {
value: old_prop[attr],
writable: false,
enumerable: true
});
}
}
Object.defineProperty(obj, prop, {
value: prop_obj,
writable: false,
enumerable: true
});
};
makePropRecursive('header');
makePropRecursive('footer');
return obj;
};
var props = new Properties({
modal_window:{
backdrop:true,
keyboard:true,
show:true,
remote:false,
type:{
normal:function(){
this.footer.button.accept.type='btn btn-primary';
this.header.type='modal-header';
},
success:function(){
this.footer.button.accept.type='btn btn-success';
this.header.type='modal-header alert alert-success';
},
info:function(){
this.footer.button.accept.type='btn btn-info';
this.header.type='modal-header alert alert-info';
},
error:function(){
this.footer.button.accept.type='btn btn-danger';
this.header.type='modal-header alert alert-error';
},
warning:function(){
this.footer.button.accept.type='btn btn-warning';
this.header.type='modal-header alert';
}
}
},
header:{
title:"Whatever",
type:"Type"
},
footer:{
button:
{
accept:{
title:'Accept',
click:undefined,
type:undefined
},
cancel:{
title:'Cancel',
click:undefined
}
}
}
});
console.log(props.header);
props.header = 17;
props.header.type = 18;
props.header.title = 19;
console.log(props.header);
props.header
未更改:输出显示
Object {title: "Whatever", type: "Type"}
Object {title: "Whatever", type: "Type"}
凌晨3点,递归函数不是,所以你只能“修复”一个对象的一个级别;此外,如果将值复制到this
而不是返回obj
,那会更好;但它不应该太难以完善它。
如果您需要更改值,可以在构造函数中设置整个对象的私有副本,然后创建一个getter(get: function(name) { return stuff.from.the.original.object }
)。
答案 4 :(得分:1)
在较新版本的JavaScript中,您可以定义属性访问的工作方式:
var yourObj = function() {
var readOnly = "cannot be changed";
return {
get readOnly() { return readOnly; },
set readOnly(v) { return; },
specialSetter: function(something) {
if (something == "magic number") {
readOnly = "oops maybe it can";
}
}
};
}();
现在代码可以获得如下值:
var theValue = yourObj.readOnly;
无需进行函数调用。但是,如果它试图更改值:
yourObj.readOnly = "hello world";
然后什么都不会发生。
setter或任何其他函数可以在需要时仍然更新访问“readOnly”属性时返回的值。但是,任何直接设置属性的尝试都不会做任何事情(除非setter函数决定它喜欢该值)。
编辑你想让“specialSetter”成为只读的,尽管没有什么能够“闯入”闭包。此外,你可能想要使用Object.defineProperty来使“readOnly”不可写,但我不知道这是否能正常运行。
答案 5 :(得分:1)
如何:Object.freeze()
您可以在此处找到更多信息:MDN Object.freeze
所以:
Object.freeze(Parameters.modal_window.header);
...
然后在您的函数中,您希望能够设置它们,解冻它们,更改它们并重新冻结它们。
您绝对无法在程序中的任何其他位置更改冻结的对象。
这适用于IE9 + chrome,firefox和safari。
答案 6 :(得分:1)
您可以使用以下显示模块模式隐藏变量并防止变更,但这不会阻止任何人更改可访问的“类型”功能。
下面的代码中,header属性已更改为_header并成为一个函数。通过将带有对象表示法的返回包装为函数而不是属性返回“type”,将属性类型更改为_type并隐藏。有人可以通过编写它来将类型函数更改为他们想要的任何东西,但它们不能更改_type的值。
var Parameters = function () {
var _modal_window = function modal_window() {
var backdrop = true,
keyboard = true,
show = true,
remote = false;
return {
type: {
normal: function () {
this.footer.button.accept.type = 'btn btn-primary';
this.header.type = 'modal-header';
},
success: function () {
this.footer.button.accept.type = 'btn btn-success';
this.header.type = 'modal-header alert alert-success';
},
info: function () {
this.footer.button.accept.type = 'btn btn-info';
this.header.type = 'modal-header alert alert-info';
},
error: function () {
this.footer.button.accept.type = 'btn btn-danger';
this.header.type = 'modal-header alert alert-error';
},
warning: function () {
this.footer.button.accept.type = 'btn btn-warning';
this.header.type = 'modal-header alert';
}
}
};
}();
var _header = function header() {
var _type = 'This causes error';//this.window.type.normal.header;
return {
title: undefined, type: function () { return _type; }
};
}();
var _footer = function footer() {
return {
button:
{
accept: {
title: 'Accept',
click: undefined,
type: undefined
},
cancel: {
title: 'Cancel',
click: undefined
}
}
};
}();
return {
modal_window: _modal_window,
header: _header,
footer: _footer
};
}();