JavaScript深度克隆(深度拷贝)一个对象

时间:2022-10-27 19:56:43

我有一个前端笔试题:使用JavaScript深度克隆一个对象。可是我发现大多数人都是空白,问他为什么不做,大部分说不懂这题目的意思。

科普一下:

js一般有两种不同数据类型的值:

基本类型(包括undefined,Null,boolean,String,Number),按值传递;

引用类型(包括数组,对象),按址传递,引用类型在值传递的时候是内存中的地址。例如:

1 var a={"a":1};
2  
3 var b=a;
4  
5 b["b"]=2;
6  
7 console.log(a);//{"a":1,"b":2};

如果你修改b的值,那么a变量的值也发生了变化。

克隆或者拷贝分为2种:浅度克隆(拷贝),深度克隆(拷贝);

浅度克隆:基本类型为值传递,对象仍为引用传递。

深度克隆:所有元素或属性均完全克隆,并于原引用类型完全独立,即,在后面修改对象的属性的时候,原对象不会被修改。

我的深度克隆代码如下:

01 function cloneObject(o) {
02         if(!o || 'object' !== typeof o) {
03             return o;
04         }
05         var temp;
06         if(o.constructor === Array){
07             //temp=o.concat();
08             temp = [];
09             var i = o.length;
10             while (i--) {
11                 temp[i] = cloneObject(o[i]);
12             }
13         }else if(o.constructor === Object){
14             temp = {}; 
15             for (var in o) {
16                 if(o.hasOwnProperty(k)){
17                     temp[k] = cloneObject(o[k]);
18                 }
19             }
20         }
21         return temp;
22     }

主要使用了递归。
不过代码看上去挺变扭的,被朋友批了一顿,数组本来就是对象,可以精简代码。优化了一下,欢迎拍砖:

1 function cloneObject(obj){
2     var o = obj.constructor === Array ? [] : {};
3     for(var in obj){
4         if(obj.hasOwnProperty(i)){
5             o[i] = typeof obj[i] === "object" ? cloneObject(obj[i]) : obj[i];
6         }
7     }
8     return o;
9 }

另:如果是一个简单的数组,元素中没有引用类型的值,可以直接用array.concat();或者array.slice(0);来深度拷贝一个数组,这样简单又高效。数组的concat()和slice()本来就会生成一个新的数组,原来的数组不会受影响。但是要注意的是你要确保被拷贝的数组中元素中没有引用类型的值。
=================2012-11-19 9:13更新===============
大家看redky评论把,最简单的深度克隆,很简单,很实用:
var s = JSON.stringify( obj );
var o = JSON.parse( s );


constructor 属性返回对创建此对象的数组函数的引用。

例子 1

在本例中,我们将展示如何使用 constructor 属性:

<script type="text/javascript">

var test=new Array();

if (test.constructor==Array){document.write("This is an Array");}if (test.constructor==Boolean){document.write("This is a Boolean");}if (test.constructor==Date){document.write("This is a Date");}if (test.constructor==String){document.write("This is a String");}</script>

输出:

This is an Array

Object 对象

Object 对象自身用处不大,不过在了解其他类之前,还是应该了解它。因为 ECMAScript 中的 Object 对象与 Java 中的 java.lang.Object 相似,ECMAScript 中的所有对象都由这个对象继承而来,Object 对象中的所有属性和方法都会出现在其他对象中,所以理解了 Object 对象,就可以更好地理解其他对象。

Object 对象具有下列属性:

constructor
对创建对象的函数的引用(指针)。对于 Object 对象,该指针指向原始的 Object() 函数。
Prototype
对该对象的对象原型的引用。对于所有的对象,它默认返回 Object 对象的一个实例。

Object 对象还具有几个方法:

hasOwnProperty(property)
判断对象是否有某个特定的属性。必须用字符串指定该属性。(例如,o.hasOwnProperty("name"))
IsPrototypeOf(object)
判断该对象是否为另一个对象的原型。
PropertyIsEnumerable
判断给定的属性是否可以用 for...in 语句进行枚举。
ToString()
返回对象的原始字符串表示。对于 Object 对象,ECMA-262 没有定义这个值,所以不同的 ECMAScript 实现具有不同的值。
ValueOf()
返回最适合该对象的原始值。对于许多对象,该方法返回的值都与 ToString() 的返回值相同。

注释:上面列出的每种属性和方法都会被其他对象覆盖。