克隆一个 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克隆为BA 对属性进行更改,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,它可以工作。 如果一个对象同时具有propertiesmethods,那么我的朋友,使用这种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 对象? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何正确克隆 JavaScript 对象?

如何正确克隆 JavaScript 对象?

如何正确克隆 JavaScript 对象?

如何正确克隆 JavaScript 对象?

如何正确克隆 JavaScript 对象?

如何正确克隆 JavaScript 对象?