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 ...
随机推荐
- VC编译错误:一个或多个多重定义的符号
1>uafxcw.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" ( ...
- Where is "Active Directory Information Extractor"?
My friend she showed me a screenshot as below yesterday. The name of this document is “EnCase Forens ...
- iOS 8.3 JB ready
Hi, I've been waiting for a very very long time..Now iOS 8.3 is ready. http://www.taig.com/ You guys ...
- 调试时屏蔽JavaScript库代码 –Chrome DevTools Blackbox功能介绍
代码难免会有Bug,每次我们在Chrome调试代码时,总是会进入各种各样的库代码(比如jQuery.Zepto),但实际上很多时候我们并不希望这样,要是能把这些库代码“拉黑”多好啊. 广大码农喜闻乐见 ...
- 007Linux在线升级yum
1.Linux下如何安装软件:利用rpm命令进行安装: 2.rpm优点:安装过程很简单,不需要做额外的配置逻辑,拿到安装包,通过rpm命令就可以安装: 3.rpm缺点: (1)需要自己四处去找和系统版 ...
- C puzzles详解
题目:http://www.gowrikumar.com/c/ 参考:http://wangcong.org/blog/archives/291 http://www.cppblog.com/smag ...
- xode View 的封装
1.Xcode自带头文件的路径 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Develo ...
- C#winform初试报表
步骤1.新建一个窗口,拖一个ReportViewer控件上去,设置该控件的Dock为Fill. 步骤2.添加一个报表文件,如:Report1.rdlc,设置其中的参数,这里设置的参数和下面的代码里面的 ...
- mysql 修改字段长度
mysql 修改字段长度 alter table news modify column title varchar(130); alter table 表名 modify column 字段名 类型 ...
- 关于Raw,Assets的使用
Raw,Assets下文件区别: 相同点:两个目录下的文件在打包后都会原封不动的保存到apk中,不会被编译成二进制. 不同点:Raw下文件不能使用目录结构, 有些格式的会被压缩,能够通过R.raw方便 ...