克隆 JavaScript 对象。 再次 :(
我知道再次阅读这个话题真的很烦人。 在开始深入研究代码之前,一种解决方案可能是我没有在 JavaScript 中获取原型和对象。 但在这一点上,我想,我愿意。
问题是:
如何克隆 JavaScript 类(使用原型创建),以便“克隆”类在之后扩展和执行时保持不变?
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
如果我没猜错的话,第二次调用 new BAR()
(在 new FOO()
之后)应该返回 BAR: BAR
,而不是目前的 BAR: FOO
。
此问题的一种可能的解决方案是完全重写 clone
函数,如下所示:
function clone(obj) {
return eval("("+obj.toString()+")"); // the same as eval(uneval(obj));
}
但这种方法有一个很大的缺点,您无法传递任何动态创建的对象。
有任何想法吗?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我只是想向任何人展示我对上述问题的解决方案。
尝试深入研究它以了解其工作原理。 有谁能看到这个实现的任何问题,内存泄漏等?
I just wanted to show anyone my solution for the problem above.
Try to dig into it to understand how this is working. Does anyone can see any problems with this implementation, memory leaks etc.?
问题是您如何克隆“原型”
以下行
您不仅克隆“原型”,还克隆“名称”属性。
如果您将上面的行替换为
您的代码现在将返回
The problem is how you are cloning the 'prototype'
The following line
You are not only cloning the 'prototype', you are also cloning the 'name' property.
If you replace above line with
Your code will now return
克隆 javascript 对象的问题是你决定要克隆多深?
考虑我有以下对象:
这意味着我必须遍历“对象”类型的所有属性,如果您有深层嵌套,这可能会变得相当昂贵。
如果您有一个简单的 1 级对象,您可以只使用简单的反射 for 循环并创建一个新的对象文字。
注意:这不会复制原始对象的方法。
The issue with cloning a javascript object is how deep do you decide to go?
Consider i have the following object:
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.
除了 SolutionYogi 提到的之外,还需要进行另一个更改。 在 FOO 中,您要传递要克隆的 BAR,但 BAR 是构造函数(BAR ==“function”的类型),因此克隆函数的第一次测试将会失败,并且您的返回值将是对未更改的 BAR 的引用。 这意味着 myBAR.prototype 不是 BAR.prototype 的克隆,而是对其的引用。
为了实际创建一个新的构造函数,而不仅仅是一个引用,我认为您必须使用 eval - 添加类似的内容:
还有其他考虑因素(正如亚历克斯指出的),但添加上述内容应该会导致您的测试用例获得成功。
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:
There are other considerations (as Alex points out), but adding the above, should cause your test case to be successful.