I have problem with create Object instance without reference.
I researched and found many people suggest using jQuery.extend
to create object without reference.
Refer: What is the most efficient way to deep clone an object in JavaScript?
But it not success in my case.
Here is my code JSBin
var MyModel = (function() { MyModel = function() {}; var myModelObj = { prop1: null, prop2: { sub1: null, sub2: null } }; MyModel.prototype = { getProp1: function() { return myModelObj.prop1; }, getSub1: function() { return myModelObj.prop2.sub1; }, getSub2: function() { return myModelObj.prop2.sub2; }, setProp1: function(val) { myModelObj.prop1 = val; }, setSub1: function(val) { myModelObj.prop2.sub1 = val; }, setSub2: function(val) { myModelObj.prop2.sub2 = val; }, getObj: function() { return $.extend({}, myModelObj); }, setObj: function(json_obj) { myModelObj.prop1 = json_obj.prop1; myModelObj.prop2.sub1 = json_obj.prop2.sub1; myModelObj.prop2.sub2 = json_obj.prop2.sub2; }, setParam: function(prop1, sub1, sub2) { myModelObj.prop1 = prop1; myModelObj.prop2.sub1 = sub1; myModelObj.prop2.sub2 = sub2; } }; return MyModel; }()); var model1 = new MyModel(); model1.setParam('prop1', 'sub1', 'sub2'); var model2 = new MyModel(); model2.setParam('clone-prop1', 'clone-sub1', 'clone-sub2'); console.log("object 1"); console.log(model1.getObj()); console.log("object 2"); console.log(model2.getObj());
My expected result is
model1 = {
prop1: 'prop1',
prop2: {
sub1: 'sub1',
sub2: 'sub2'
}
}
model2 = {
prop1: 'clone-prop1',
prop2: {
sub1: 'clone-sub1',
sub2: 'clone-sub2'
}
}
But actually, model1
and model2
have same data of model2
.
Can someone point me out where i made mistake?
=== Update ===
@arcyqwerty's solution help me solved create object without reference.
var MyModel = function() { this.prop1 = null; this.prop2 = { sub1: null, sub2: null }; }; MyModel.prototype = { getProp1: function() { return this.prop1; }, getSub1: function() { return this.prop2.sub1; }, getSub2: function() { return this.prop2.sub2; }, setProp1: function(val) { this.prop1 = val; }, setSub1: function(val) { this.prop2.sub1 = val; }, setSub2: function(val) { this.prop2.sub2 = val; }, getObj: function() { return $.extend({}, this); }, setObj: function(json_obj) { this.prop1 = json_obj.prop1; this.prop2.sub1 = json_obj.prop2.sub1; this.prop2.sub2 = json_obj.prop2.sub2; }, setParam: function(prop1, sub1, sub2) { this.prop1 = prop1; this.prop2.sub1 = sub1; this.prop2.sub2 = sub2; } }; var model1 = new MyModel(); model1.setParam('prop1', 'sub1', 'sub2'); var model2 = new MyModel(); model2.setParam('clone-prop1', 'clone-sub1', 'clone-sub2'); console.log("object 1"); console.log(model1.getObj()); console.log("object 2"); console.log(model2.getObj());
But I also want use encapsulation
feature in OOP
. It means, we only get value object, property through get
function. Is it possible on Javascript
? It explain why i have an object inside Model (but it reference on same object)
Thank you very much!
Try this
var MyModel = function() {
this.prop1 = null;
this.prop2 = {
sub1: null,
sub2: null
};
};
MyModel.prototype = {
getProp1: function() {
return this.prop1;
},
getSub1: function() {
return this.prop2.sub1;
},
getSub2: function() {
return this.prop2.sub2;
},
setProp1: function(val) {
this.prop1 = val;
},
setSub1: function(val) {
this.prop2.sub1 = val;
},
setSub2: function(val) {
this.prop2.sub2 = val;
},
getObj: function() {
return $.extend({}, this);
},
setObj: function(json_obj) {
this.prop1 = json_obj.prop1;
this.prop2.sub1 = json_obj.prop2.sub1;
this.prop2.sub2 = json_obj.prop2.sub2;
},
setParam: function(prop1, sub1, sub2) {
this.prop1 = prop1;
this.prop2.sub1 = sub1;
this.prop2.sub2 = sub2;
}
};
var model1 = new MyModel();
model1.setParam('prop1', 'sub1', 'sub2');
var model2 = new MyModel();
model2.setParam('clone-prop1', 'clone-sub1', 'clone-sub2');
console.log("object 1");
console.log(model1.getObj());
console.log("object 2");
console.log(model2.getObj());
The problem with your original constructor is that instances of MyModel
, although different objects created with the new
keyword, all share the same myModelObj
(which is only ever created once). Using this solution, new fields are created each time you craete a new MyModel
.
This is similar to having MyModel = function() { this.myModelObj = {...}; }
MyModel = function() { this.myModelObj = {...}; }
and accessing fields using this.myModelObj.prop
but at that point, myModelObj
is a bit redundant as you can just set the properties on this
directly.
Also, using this solution, you can use model1.prop
directly without having to say model1.getObj().prop
(although that works too)
--
Note: it's also a little strange for me to see
var ClassName = (function() {
ClassName = function() { ...; };
ClassName.prototype = { ... };
return ClassName;
})();
Is there a reason you're doing that instead of
var ClassName = function() { ... };
ClassName.prototype = { ... };
?
I suppose it makes sense in the original code if you didn't want to pollute the namespace with myModelObj
, but it seems unnecessary otherwise.
--
Edit: encapsulation
If you require an object's properties to be set through getters/setters, you could try something like this:
var MyModel = function() {
var privateObject = {
prop1: null,
prop2: {
sub1: null,
sub2: null
}
};
Object.defineProperty(this, 'prop1', {
get: function() {
console.log('Getting prop1 through getter');
return privateObject.prop1;
},
set: function(value) {
console.log('Setting prop1 through setter');
privateObject.prop1 = value;
}
});
};
The downside is that you won't be able to share getter/setter functions using the prototype chain, meaning you'll have a lot of function objects hanging around. For a small number of instances, this is probably fine (performance-wise). It will also affect inheritance, if your class has subclasses.
If you're on a platform without defineProperty
, you can also replicate this by keeping the var privateObject
in the constructor and using this.getProp1 = function() { return privateObject.prop1; }
this.getProp1 = function() { return privateObject.prop1; }
in the constructor instead of on the prototype. The net effect is similar to using defineProperty
.
--
Edit: or using getter/setter syntax
Note : the returned object is not an instanceof
F
.
function F() {
var fields = { prop: null };
return {
get prop() {
console.log("getter");
return fields.prop;
},
set prop(value) {
console.log("setter");
fields.prop = value;
}
};
}
f = new F
f.prop = 123
f.prop
This variant of arcyqwerty's answer demonstrates a much deeper encapsulation of your data. The trade-off is that each instance gets its own copy of the methods, rather than sharing them at a "class" level:
var MyModel = function() {
var prop1 = null;
var prop2 = {
sub1: null,
sub2: null
};
this.getProp1 = function() {
return prop1;
};
this.getSub1 = function() {
return prop2.sub1;
};
this.getSub2 = function() {
return prop2.sub2;
};
this.setProp1 = function(val) {
prop1 = val;
};
this.setSub1 = function(val) {
prop2.sub1 = val;
};
this.setSub2 = function(val) {
prop2.sub2 = val;
};
this.getObj = function() {
return {
prop1: prop1,
prop2: {
sub1: prop2.sub1,
sub2: prop2.sub2
}
};
};
this.setObj = function(json_obj) {
prop1 = json_obj.prop1;
prop2.sub1 = json_obj.prop2.sub1;
prop2.sub2 = json_obj.prop2.sub2;
};
this.setParam = function(_prop1, _sub1, _sub2) {
prop1 = _prop1;
prop2.sub1 = _sub1;
prop2.sub2 = _sub2;
};
};
You said,
But I wonder how we protect properties on
Javascript
?
I think that's the wrong question. JS is a different language, with different concerns than, say, Java or Ruby. It is at least as much a functional language as an OO one. You probably should not try to act as though you're working in Java when you're doing JS, but learn its folkways instead.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.