克隆一个 JavaScript 对象? [复制]
Posted
技术标签:
【中文标题】克隆一个 JavaScript 对象? [复制]【英文标题】:Cloning a JavaScript object? [duplicate] 【发布时间】:2011-04-15 23:57:29 【问题描述】:可能重复:How to clone js object?
这是创建 javascript 对象的另一种方法(使用对象文字表示法而不是函数):
user =
name: "Foo",
email: "bar@baz.com"
有没有办法克隆这个对象还是单例?
【问题讨论】:
JavaScript 对象 != JSON 对象。您提供的示例是 JavaScript 对象文字;我相应地更新了你的帖子。 好问题!我一直认为 user2 = user 会复制,但不会。 最短的“答案”:是的,是的。 ;) 您选择的答案仍然不是深拷贝..我的解决方案仍然是最好的。 您选择的答案不会产生与使用var user2 = user;
不同的结果。只有clone
函数导致构造函数名称发生更改。 那不是克隆,那是重复引用!!
【参考方案1】:
试试这个:
var clone = (function()
return function (obj) Clone.prototype=obj; return new Clone() ;
function Clone()
());
这是发生了什么。
Clone 是一个虚拟构造函数。 我们将要克隆的对象分配给 Clone 构造函数的原型。 我们使用“new”调用 Clone,因此构造的对象将原始对象作为其构造函数的原型,也称为(非标准)__proto__
。
克隆的对象将共享原始对象的所有属性,而不会复制任何内容。如果为克隆对象的属性分配了新值,它们将不会干扰原始对象。并且不需要篡改内置函数。
请记住,新创建对象的对象属性将引用与克隆对象的同名属性相同的对象。为克隆的属性分配新值不会干扰原始值,但为克隆的对象属性分配值会。
在 chrome 或 firebug 控制台中试试这个:
var user =
name: "Foo",
email: "bar@baz.com"
var clonedUser = clone(user);
console.dir(clonedUser);
这种克隆技术的详细解释可以在here找到。
【讨论】:
user=name:"",email:"",obj:a:"A"; clonedUser=clone(user);
, clonedUser.obj.a="B";
你会发现user.obj.a == "B"
这看起来也和 Chris J 的回答非常相似。
vol7ron:是的,因为 user.obj 和 clonedUser.obj 指的是同一个对象。为 newUser 的 obj
属性分配新值不会出现此行为。请求是克隆,不是副本,也不是深层副本。请参阅我答案末尾的链接。
@no: 很好,如果你编辑答案,我会删除我的反对票 :) 没错,但是文章对程序化 clone
的定义和克隆的白话定义。
静态文章定义A
克隆为B
。 A
对属性进行更改,B
看到它。 B
更改属性,A
没有给出 ----。在您的示例中,它们都将共享一个嵌套对象。如果B
更改了该对象的属性,A
不应该看到更改。总之,不鼓励克隆,鼓励深度复制。【参考方案2】:
您可以使用 JSON 对象(存在于现代浏览器中):
var user = name: "Foo", email: "bar@baz.com"
var user2 = JSON.parse(JSON.stringify(user))
user2.name = "Bar";
alert(user.name + " " + user2.name); // Foo Bar
见jsfiddle。
编辑
如果您在旧版浏览器中需要此功能,请参阅 http://www.json.org/js.html。
【讨论】:
嗯...不会对您投反对票,但我认为这很愚蠢。首先,如果你要使用 JSON,你需要在你的页面中包含 json2.js,因为仍然有当前的浏览器没有原生 json,并且在一段时间内会有一些常用的浏览器不是最新的。要么编写或借用扩展实现,要么包含一个库。 我只是提供另一种方法来做到这一点。如果一个站点已经有 json2.js,它可以工作。 如果一个对象同时具有properties
和methods
,那么我的朋友,使用这种JSON 样式,methods
没有被克隆
其实没那么傻...例如,如果您正在为嵌入式系统创建应用程序,那么您始终知道它将在什么浏览器上运行;并且您知道它是一个数据对象(因此您不在乎方法是否被克隆),那么这很容易,干净且安全。它不适用于所有应用程序,但它非常适合我想要的!谢谢!【参考方案3】:
我喜欢用这个:
if (typeof Object.create !== 'function')
Object.create = function (o)
var F = function () ;
F.prototype = o;
return new F();
;
那么我想克隆的任何对象都可以这样做:
user =
name: "Foo",
email: "bar@baz.com"
;
var user2 = Object.create(user);
如(或类似于)JavaScript The Good Parts 中所示
【讨论】:
你不应该这样做;见Kangax' answer @Marcel 感谢您指出这一点。我将保留我的答案,并推荐 Kangax 的解释作为一个很好的阅读。 @Marcel/Chris +1; Kangax 的答案只是 create 不会在任何地方都有两个属性。我的感觉是,如果每个人都使用这种方法,那么它将迫使供应商遵守标准。我最初没有使用 FF,因为它没有正确显示所有内容,现在网络变得更智能,FF 进行了修改以在 quirksmode 下更好地工作。如果程序员局限于标准并推动接受它们的浏览器,情况也是如此。 如果 Javascript 可以提供一种克隆对象的简单方法会很好 我最喜欢那个。【参考方案4】:大多数 javascript 框架对对象克隆都有很好的支持。
var a= 'key':'value';
var b= jQuery.extend( true, , a );
【讨论】:
同意:underscorejs 也有克隆方法underscorejs.org/#clone【参考方案5】:Object.prototype.clone = function clone(obj)
obj = obj || this;
var new_obj = ;
for( var p in obj )
if ( obj.hasOwnProperty(p) )
if( obj[p] !== null && typeof(obj[p]) === "object" )
new_obj[p] = clone( obj[p] );
else
new_obj[p] = obj[p];
return new_obj;
;
/* Example */
var foo =
name: "Foo"
, email: "bar@baz.com"
, obj: a:"A",b:"B"
;
var bar = foo.clone();
bar.name = "Bar";
bar.obj.b = "C";
// foo and bar should have a different 'name'
// foo and bar should retain the same email
// foo and bar should have different values for <foo/bar>['obj']['b']
// foo and bar should have the same values for <foo/bar>['obj']['a']
console.dir(foo);
console.dir(bar);
【讨论】:
不不不...永远不要弄乱 Object.prototype,你会破坏一切:P 这是不正确的,除非您是使用JQuery
的无人机之一,否则永远不要搞砸任何事情并忘记如何做任何事情。
别生气。我通常避免使用 jQuery。不过有两件事... 1,这不是克隆,而是副本。 “克隆”这个名称与这种技术相关:oranlooney.com/functional-javascript
2,不要乱用 Object 和 Array 之类的内置函数,不是因为 jQuery,而是因为有人在使用 in
迭代对象时会忘记使用 hasOwnProperty,突然他们就会有额外的属性,因为另一个开发人员在他们不知情的情况下修改了内置函数。
@no: 你提出了一个要记住的有效观点,但我认为这不足以从本质上说“不要乱用原型”。以上是关于克隆一个 JavaScript 对象? [复制]的主要内容,如果未能解决你的问题,请参考以下文章