【问题标题】:Cloning a JavaScript object? [duplicate]克隆一个 JavaScript 对象? [复制]
【发布时间】: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 函数导致构造函数名称发生更改。 那不是克隆,那是重复引用!!

标签: javascript


【解决方案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 );

【讨论】:

【解决方案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: 你提出了一个要记住的有效观点,但我认为这不足以从本质上说“不要乱用原型”。
猜你喜欢
  • 2019-11-18
  • 2015-01-08
  • 2013-04-06
  • 2011-12-19
  • 1970-01-01
  • 2011-10-17
  • 2013-01-03
  • 2013-02-18
  • 2014-01-11
相关资源
最近更新 更多