转载:http://blog.csdn.net/wanmingtom/article/details/7988284

这原本是StackOverFlow里的一个提问,看到答案后受益良多,于是翻译一下下跟大家分享,原文地址:http://stackoverflow.com/questions/4459928/how-to-deep-clone-in-javascript

浅复制我就不说了,全部是引用对象,网上列出的深复制的几个例子也都有或多或少的问题,我都试过,某些特殊情况下会出现奇怪的问题,这里摆出一个比较完美的深复制函数(别直接复制了拿去用哦,里面有互动的内容):

上面的这个函数复制一些{}里的玩意儿一点问题都没有,考虑的情况很全面,很周全。但是,现在还没算完,我们来讨论下,如何复制一个“真正”的对象,比如你通过构造函数建立了个对象:

  1. var User = function(){};
  2. var newuser = new User();

这种情况的话用上面的函数是完全没问题的,所有的对象的属性全部暴露在外,换句话说都是公有的,public的,随便访问的,没有问题。你可以用for in去迭代里面的属性,不管什么类型,去掉那个“false &&”就可以用,完全没问题。但是,这里存在着一个风险--要知道,对象或实例的属性不可能全部是公有的,一旦存在私有变量(原文中叫状态state),你这样的复制便毫无意义,因为会丢失这些数据。比如下面的代码:

  1. function Man() {
  2. var age = 1;
  3. this.getAge = function () {
  4. return age;
  5. }
  6. this.grow = function () {
  7. age += 1;
  8. }
  9. }
  10. var man = new Man();

里面的age这个东东,就会出现复制不了的情况了。

除此之外,还有另外一个问题,想象一个没有这些私有变量的情况下,这些代码木有问题,但是,一些对象的构造函数是有参数的,比如我要这样建立一个对象:

function clone(item) {
if (!item) { return item; } // null, undefined values check var types = [ Number, String, Boolean ],
result; // normalizing primitives if someone did new String('aaa'), or new Number('444');
//一些通过new方式建立的东东可能会类型发生变化,我们在这里要做一下正常化处理
//比如new String('aaa'), or new Number('444')
types.forEach(function(type) {
if (item instanceof type) {
result = type( item );
}
}); if (typeof result == "undefined") {
if (Object.prototype.toString.call( item ) === "[object Array]") {
result = [];
item.forEach(function(child, index, array) {
result[index] = clone( child );
});
} else if (typeof item == "object") {
// testign that this is DOM
//如果是dom对象,那么用自带的cloneNode处理
if (item.nodeType && typeof item.cloneNode == "function") {
var result = item.cloneNode( true );
} else if (!item.prototype) { // check that this is a literal
// it is an object literal
//如果是个对象迭代的话,我们可以用for in 迭代来赋值
result = {};
for (var i in item) {
result[i] = clone( item[i] );
}
} else {
// depending what you would like here,
// just keep the reference, or create new object
//这里解决的是带构造函数的情况,这里要看你想怎么复制了,深得话,去掉那个false && ,浅的话,维持原有的引用,  
//但是我不建议你去new一个构造函数来进行深复制,具体原因下面会解释
if (false && item.constructor) {
// would not advice to do that, reason? Read below
//朕不建议你去new它的构造函数
result = new item.constructor();
} else {
result = item;
}
}
} else {
result = item;
}
} return result;
} var copy = clone({
one : {
'one-one' : new String("hello"),
'one-two' : [
"one", "two", true, "four"
]
},
two : document.createElement("div"),
three : [
{
name : "three-one",
number : new Number("100"),
obj : new function() {
this.name = "Object test";
}
}
]
})
  1. new User({
  2. bike : someBikeInstance
  3. });

这种情况下你估计要悲剧,someBikeInstance这货很有可能是在另外的一些上下文中创建的,这个我们获取不来的,至少对于这个函数来说是这样。。

那该咋办呢?其实没什么好的解决办法,要么用for in去迭代,丢掉那些私有变量,要么还是用引用,这些都会出现或多或少的问题,另外一个解决方案是在所有的要被复制的对象里单独建立一个复制函数的属性,就像DOM里的复制节点函数cloneNode一样。

初次翻译,有错误的话,还望谅解!^_^

JavaScript深复制的更多相关文章

  1. javascript中关于深复制与浅复制的问题

    在javascript中,变量的类型分为基本类型和引用类型. 对于基本类型的变量来说,值的复制以及作为函数参数实参传递的过程都是值的复制传递,换句话说,是会在内存中开辟出一个新空间用于存放新的值的.这 ...

  2. Javascript中的一种深复制实现

    在javascript中,所有的object变量之间的赋值都是传地址的,可能有同学会问哪些是object对象.举例子来说明可能会比较好: typeof(true) //"boolean&qu ...

  3. 深度解析javascript中的浅复制和深复制

    原文:深度解析javascript中的浅复制和深复制 在谈javascript的浅复制和深复制之前,我们有必要在来讨论下js的数据类型.我们都知道有Number,Boolean,String,Null ...

  4. JavaScript 复制对象【Object.assign方法无法实现深复制】

    在JavaScript这门语言中,数据类型分为两大类:基本数据类型和复杂数据类型.基本数据类型包括Number.Boolean.String.Null.String.Symbol(ES6 新增),而复 ...

  5. JavaScript对象深复制

    1.原理 使用JSON,当然需要JSON安全的格式,JSON安全请参考:http://www.cnblogs.com/mengfangui/p/8257269.html 2.示例 <!DOCTY ...

  6. JavaScript实现深拷贝(深复制) 面试题

    1.两种方法实现深拷贝(深复制) (1)方法一:兼容性好,请仔细看代码(网上大部分代码有Bug) (2)方法二:需要对象满足JSON数据格式.JOSN数据格式:http://www.cnblogs.c ...

  7. javascript 中的深复制 和 其实现方法

    首先,我们需要明白什么是深复制(侧重指对象方面)? 在javascript中,复制分为浅复制和深复制,个人理解,浅复制就是直接将引用复制,复制前后的两个对象指向同一个内存地址,对其中一个进行操作,另外 ...

  8. javascript中的浅复制和深复制

    //浅复制:实现基本类型的复制没有问题,但是复制的是引用类型的话,则修改child将会修改parent function extend(parent,child){ var child = child ...

  9. javascript多种继承方式(函数式,浅复制,深复制,函数绑定和借用)

    函数式继承: var object = function (obj) { if (typeof Object.create !== 'undefined') { return Object.creat ...

随机推荐

  1. Magento后台界面全局样式修改之——font-weight

    路径: \app\design\adminhtml\Magento\backend\web\app\setup\styles\less\lib\_variables.less

  2. storm启动分析

    一个topology的启动包括了三个步骤 1)创建TopologyBuilder,设置输入源,输出源 2)获取config 3)提交topology(这里不考虑LocalCluster本地模式) 以s ...

  3. 现代福尔摩斯 - Oxygen Forensic Suite

    各位可曾听说过智能手机取证软件Oxygen Forensic Suite,它的logo是名侦探福尔摩斯一手抽着他的招牌雪茄,一手拿着放大镜,全神贯注地正进行调查工作. 使用过它的取证人员必定会对它的提 ...

  4. eclipse 导入jar包

    我们在用Eclipse开发程序的时候,经常想要用到第三方的jar包.这时候我们就需要在相应的工程下面导入这个jar包.以下配图说明导入jar包的步骤. 1.右击工程的根目录,点击Properties进 ...

  5. Android开发教程 录音和播放

    首先要了解andriod开发中andriod多媒体框架包含了什么,它包含了获取和编码多种音频格式的支持,因此你几耍轻松把音频合并到你的应用中,若设备支持,使用MediaRecorder APIs便可以 ...

  6. MySQL: InnoDB 还是 MyISAM?

    MyISAM存储引擎 MyISAM是 默认存储引擎.它基于更老的ISAM代码,但有很多有用的扩展.MyISAM存储引擎的一些特征:·      所有数据值先存储低字节.这使得数据机和操作系统分离.二进 ...

  7. C++判断五位以内的对称素数

    题目内容:判断一个数是否为对称且不大于五位数的素数. 输入描述:输入数据含有不多于50个的正整数n(0<n<232). 输出描述:对于每个n,如果该数是不大于五位数的对称素数,则输出“Ye ...

  8. javascript绑定时间 含(IE)

    script language = "javascript" type = "text/javascript"> function test(){ win ...

  9. HTML5 的新的表单属性

    本章讲解涉及 <form> 和 <input> 元素的新属性. 新的 form 属性: autocomplete novalidate 新的 input 属性: autocom ...

  10. jquery 匹配select下拉框与列表框

    今天工作中用到 GrapyCity 的 wijmo ui 控件. 要给系统中所有类型的控件加统一样式 用法 $("input [type='text']").wijtext(); ...