JavaScript深复制
转载:http://blog.csdn.net/wanmingtom/article/details/7988284
这原本是StackOverFlow里的一个提问,看到答案后受益良多,于是翻译一下下跟大家分享,原文地址:http://stackoverflow.com/questions/4459928/how-to-deep-clone-in-javascript
浅复制我就不说了,全部是引用对象,网上列出的深复制的几个例子也都有或多或少的问题,我都试过,某些特殊情况下会出现奇怪的问题,这里摆出一个比较完美的深复制函数(别直接复制了拿去用哦,里面有互动的内容):
上面的这个函数复制一些{}里的玩意儿一点问题都没有,考虑的情况很全面,很周全。但是,现在还没算完,我们来讨论下,如何复制一个“真正”的对象,比如你通过构造函数建立了个对象:
- var User = function(){};
- var newuser = new User();
这种情况的话用上面的函数是完全没问题的,所有的对象的属性全部暴露在外,换句话说都是公有的,public的,随便访问的,没有问题。你可以用for in去迭代里面的属性,不管什么类型,去掉那个“false &&”就可以用,完全没问题。但是,这里存在着一个风险--要知道,对象或实例的属性不可能全部是公有的,一旦存在私有变量(原文中叫状态state),你这样的复制便毫无意义,因为会丢失这些数据。比如下面的代码:
- function Man() {
- var age = 1;
- this.getAge = function () {
- return age;
- }
- this.grow = function () {
- age += 1;
- }
- }
- 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";
}
}
]
})
- new User({
- bike : someBikeInstance
- });
这种情况下你估计要悲剧,someBikeInstance这货很有可能是在另外的一些上下文中创建的,这个我们获取不来的,至少对于这个函数来说是这样。。
那该咋办呢?其实没什么好的解决办法,要么用for in去迭代,丢掉那些私有变量,要么还是用引用,这些都会出现或多或少的问题,另外一个解决方案是在所有的要被复制的对象里单独建立一个复制函数的属性,就像DOM里的复制节点函数cloneNode一样。
初次翻译,有错误的话,还望谅解!^_^
JavaScript深复制的更多相关文章
- javascript中关于深复制与浅复制的问题
在javascript中,变量的类型分为基本类型和引用类型. 对于基本类型的变量来说,值的复制以及作为函数参数实参传递的过程都是值的复制传递,换句话说,是会在内存中开辟出一个新空间用于存放新的值的.这 ...
- Javascript中的一种深复制实现
在javascript中,所有的object变量之间的赋值都是传地址的,可能有同学会问哪些是object对象.举例子来说明可能会比较好: typeof(true) //"boolean&qu ...
- 深度解析javascript中的浅复制和深复制
原文:深度解析javascript中的浅复制和深复制 在谈javascript的浅复制和深复制之前,我们有必要在来讨论下js的数据类型.我们都知道有Number,Boolean,String,Null ...
- JavaScript 复制对象【Object.assign方法无法实现深复制】
在JavaScript这门语言中,数据类型分为两大类:基本数据类型和复杂数据类型.基本数据类型包括Number.Boolean.String.Null.String.Symbol(ES6 新增),而复 ...
- JavaScript对象深复制
1.原理 使用JSON,当然需要JSON安全的格式,JSON安全请参考:http://www.cnblogs.com/mengfangui/p/8257269.html 2.示例 <!DOCTY ...
- JavaScript实现深拷贝(深复制) 面试题
1.两种方法实现深拷贝(深复制) (1)方法一:兼容性好,请仔细看代码(网上大部分代码有Bug) (2)方法二:需要对象满足JSON数据格式.JOSN数据格式:http://www.cnblogs.c ...
- javascript 中的深复制 和 其实现方法
首先,我们需要明白什么是深复制(侧重指对象方面)? 在javascript中,复制分为浅复制和深复制,个人理解,浅复制就是直接将引用复制,复制前后的两个对象指向同一个内存地址,对其中一个进行操作,另外 ...
- javascript中的浅复制和深复制
//浅复制:实现基本类型的复制没有问题,但是复制的是引用类型的话,则修改child将会修改parent function extend(parent,child){ var child = child ...
- javascript多种继承方式(函数式,浅复制,深复制,函数绑定和借用)
函数式继承: var object = function (obj) { if (typeof Object.create !== 'undefined') { return Object.creat ...
随机推荐
- Spring框架搭建遇到的问题汇总
1.The resource is not on the build path of a Java project 然后把相应的依赖加入构建路径 2.Type mismatch: cannot con ...
- Android异常一、异步任务导致的窗口句柄泄漏问题(转)
05-05 10:36:41.009: E/WindowManager(4243): Activity com.tao.MyActivity has leaked window com.android ...
- 搭建高性能计算环境(九)、应用软件的安装之gaussian 09
高斯软件一般使用的都是编译好的二进制版,所以解压缩后设置一下环境变量就可以用了. cd /opt tar xvf g09.tar.gz 设置环境变量,添加到/etc/profile文件中,重新登录后生 ...
- Sqlserver数据库存储路径的修改
Sqlserver数据库存储路径的修改 Sqlserver数据库存储路径问题:本系统sqlserver路径默认是存储在C盘目录下的,由于数据会慢慢变大和避免重装系统数据丢失等问题,最好手动将路径设置在 ...
- kettle的hello world
本篇介绍使用kettle的一个最简单的例子,可以初步了解下转换. 需求是这样的: 存在一个本地csv文件,文件的内容如下 现在需要将csv中的数据保存到本地的文本文件中 1.创建一个转换,并且重命名 ...
- Java 中的抽象类及接口
抽象类使用 abstract 关键字修饰,该类即为抽象类. 抽象类的作用: 1.某些情况下,父类约束子类必须包含哪些方法,但不知道子类如何去实现这些方法. 2.可以从多个具有相同特征的类中抽象出一个抽 ...
- Internet Explorer 无法启用 JavaScript 怎么办?
在 Internet Expllorer 8/9 中,有些同学在浏览网页时,收到提示:“需要启用 JavaScript …”,并且会发现网页上某些功能不能用了,比如点击网页里的按钮没反应等等. 怎么启 ...
- Nginx Location配置语法介绍、优先级说明
nginx 语法规则:location [=|~|~*|^~|!~|!~*] /uri/ { … } location匹配的是$document_uri,$document_uri 会随 ...
- 容易被忽略的事----sql语句中select语句的执行顺序
关于Sql中Select语句的执行顺序,一直很少注意这个问题,对于关键字的使用也很随意,至于效率问题,因为表中的数据量都不是很大,所以也不是很在意. 今天在一次面试的时候自己见到了,感觉没一点的印象, ...
- Partitioner没有被调用的情况
map的输出,通过分区函数决定要发往哪个reducer. 有2种情况,我们自定义的Partitioner不会被调用 1) reducer个数为0 这种情况,没有reducer,不需要分区 2) red ...