Reputation: 439
I know it is really annoying to read this topic again. Before you start diggin into the code, one solution could be that I don't get prototypes and objects in JavaScript. But at this point i think, i do.
The problem is:
How to clone an JavaScript Class (created with prototypes), so that the “cloned” Class remains untouched when extending and executing afterwards?
function clone(obj){
if(obj == null || typeof(obj) != 'object')
return obj;
var temp = new obj.constructor();
for(var key in obj)
temp[key] = clone(obj[key]);
return temp;
}
var FOO = function() {
var myBAR = clone(BAR);
myBAR.prototype = jQuery.extend(true, myBAR.prototype, this); // deep cloning twice and extending with this
console.log("FOO:", this.name);
new myBAR();
};
FOO.prototype = {
name: "FOO"
};
var BAR = function() {
console.log("BAR:", this.name);
};
BAR.prototype = {
name: "BAR"
};
new FOO(); // returns FOO: FOO and BAR: FOO
new BAR(); // returns BAR: FOO should return BAR: BAR
If i've got it right, the second call of new BAR()
(after new FOO()
) should return BAR: BAR
not BAR: FOO
as at the moment.
One possible solution for this problem is an complete rewrite of the clone
function in something like this:
function clone(obj) {
return eval("("+obj.toString()+")"); // the same as eval(uneval(obj));
}
But this approach has an BIG downside, you can't pass any dynamically created objects.
Any ideas?
Upvotes: 1
Views: 2035
Reputation: 439
I just wanted to show anyone my solution for the problem above.
function cloneClass (func) {
if(typeof func == 'function') {
var prototype = {};
for (var prop in func.prototype) {
prototype[prop] = func.prototype[prop];
};
var Class = function() {
var _this = this;
var constructor = function() {
func.apply(_this, arguments);
};
constructor.prototype = _this;
for (var property in func) {
if(property != "prototype") {
constructor[property] = func[property];
}
};
return constructor;
};
Class.prototype = prototype;
return new Class();
}
return func;
};
Try to dig into it to understand how this is working. Does anyone can see any problems with this implementation, memory leaks etc.?
Upvotes: 0
Reputation: 169613
function clone(obj) {
if(typeof obj !== 'undefined') {
clone.prototype = Object(obj);
return new clone;
}
}
function Foo() {} // base class
function Bar() {} // derived class
Bar.prototype = clone(Foo.prototype); // inherit from `Foo.prototype`
Upvotes: 0
Reputation: 146
There is an another change that needs to be made, in addition to that mentioned by SolutionYogi. In FOO, you're passing BAR to be cloned, but BAR is constructor (typeof BAR == "function"), so it's going to fail the first test the clone function, and your return value will be a reference to an unchanged BAR. And that means myBAR.prototype is not a clone of BAR.prototype, but a reference to it.
In order to actually create a new constructor, not just a ref, I think you'll have to use eval--adding something like:
if (typeof obj == "function) {
eval("var temp = " + obj + ";");
return temp;
}
There are other considerations (as Alex points out), but adding the above, should cause your test case to be successful.
Upvotes: 0
Reputation: 32243
The problem is how you are cloning the 'prototype'
The following line
myBAR.prototype = jQuery.extend(true, myBAR.prototype, this); // deep cloning
You are not only cloning the 'prototype', you are also cloning the 'name' property.
If you replace above line with
myBAR.prototype = jQuery.extend(true, myBAR.prototype, this.prototype); // deep cloning
Your code will now return
new FOO(); // returns FOO:FOO and BAR:BAR
new BAR(); // returns BAR:BAR
Upvotes: 1
Reputation: 36586
The issue with cloning a javascript object is how deep do you decide to go?
Consider i have the following object:
var obj = {
prop : {
n1prop : {
hello : 'world';
}
}
};
This means i would have to traverse all properties that are of type 'object' which could get quite expensive if you have a deep nesting.
If you have a simple 1 level object you could just use a simple reflection for loop and create a new object literal. NOTE: This won't copy methods of the original object.
function clone(obj) {
var cloned;
if (obj && typeof obj === 'object') {
cloned = {};
for (var p in obj) {
if (obj.hasOwnProperty(p) && typeof obj[p] !== 'function') {
cloned[p] = obj[p]
}
}
return cloned;
}
else {
return null;
}
}
Upvotes: 0