轉(zhuǎn)自:http://blog.csdn.net/qq_27090183/article/details/50823429
使用遞歸來實現(xiàn)一個深度克隆财忽,可以復制一個目標對象,返回一個完整拷貝
被復制的對象類型會被限制為數(shù)字泣侮、字符串即彪、布爾、日期、數(shù)組隶校、Object對象漏益。不會包含函數(shù)、正則對象等
首先要去判斷要克隆的對象的值類型或者引用類型深胳。判斷方法有很多種绰疤!
對于值類型或者引用有4種方法判斷:
1.typeof
但是!js的數(shù)值有兩種構(gòu)造方法:直接賦值法和通過值函數(shù)構(gòu)造器構(gòu)造
例如:
var test1 = "string";
var test2 = new String("string2");
console.log(typeof test1);//輸出string
console.log(typeof test2);//輸出object
對于typeof
來說舞终;所有通過構(gòu)造器constructor
產(chǎn)生的變量都是object
.那么我們怎么去判斷用constructor
產(chǎn)生的變量轻庆?
2.instanceof
instanceof
函數(shù)可以判斷左邊參數(shù)是否是右邊參數(shù)的一個實例!
例如:
console.log(test2 instanceof String);//輸出true
console.log(test1 instanceof String);//輸出false
這就很不和諧了敛劝!有沒有兩種都能判斷的方法呢余爆?
3.Object.prototype.toString.call()
當然有!MDN在官方教程上就介紹了一種可以判斷所有類型的方法夸盟!
使用toString()方法來檢測對象類型
console.log(Object.prototype.toString.call(test1))//輸出[object String]
console.log(Object.prototype.toString.call(test1))//輸出[object String]
頓時覺得人生豁然開朗了起來蛾方!啊~五環(huán)!你比四環(huán)多一環(huán)满俗!
4.Object.constructor
在研究MDN 的api文檔的時候转捕,發(fā)現(xiàn)了constructor
方法!
無論怎么樣唆垃,這個方法都返回一個指向創(chuàng)建了該對象原型的函數(shù)引用。
需要注意的是痘儡,該屬性的值是那個函數(shù)本身辕万, 而不是一個包含函數(shù)名稱的字符串!
對于原始值(如1沉删,true 或 “test”)渐尿,該屬性為只讀。 所有對象都會從它的原型上繼承一個constructor
屬性. 所以矾瑰,雖然可以實現(xiàn)判斷砖茸,但是還是不用為好!
console.log(test1.constructor.toString()=="function String() { [native code] }")//true;
console.log(test2.constructor.toString()=="function String() { [native code] }")//true;
總結(jié):方法3殴穴、4對于所有值類型和引用類型適用(推薦第三種方法凉夯,畢竟官方),第12種方法看情況使用采幌!
然后來到遍歷問題了劲够!
1.字符串的遍歷
var temp = src.split("");
var cloneString="";
for(var i=0;i<temp.length;i++)
{
cloneString+=temp[i];
}
原理就是利用split()
方法將字符串里一個個字母分開(注意里面的參數(shù)為空 "",為其他就會以這個參數(shù)為標準分離字符串)
2.數(shù)組的遍歷
使用的是傳統(tǒng)的數(shù)組遍歷
var temp = new Array();
for(var i=0,a;a = array[i];i++)
{
temp[i] = cloneObject(a);
}
這里遇到了幾個坑,先說一下: 當使用
for(var a in array)
{
console.log(a+typeof a)
}
得到的值是 0 string 1 string 2 string
這種方法并不行 還有一個坑就是當使用
for(var i=0,a;a = array[i++];)
時 i會在a
被賦值后就自動增加而不是等到一個循環(huán)完成再增加 休傍;也就是遍歷結(jié)果是對的征绎,但是i
的數(shù)值變化是從1
開始而不是從0
開始的!
在賦值的過程中磨取,我首先使用的是temp.push()
方法人柿!但是柴墩!push
方法會讓temp
數(shù)組新增加的元素的類型為undefined
!這不是我想要的結(jié)果凫岖!我要的是完美克隆江咳,即數(shù)組里面對象類型也要和原來的一致。
看了MDN的api接口發(fā)現(xiàn)解決方法如下:
Array.prototype.push.apply(temp,array);
3.對象的遍歷
var temp = {}; var keys = Object.keys(src); // keys 為對象src的鍵名字數(shù)組
// 它是數(shù)組0亍T住!
for(var i=0,a;a=keys[i];i++)
{
temp[a] = cloneObject(src[a]);
}
對象的遍歷婶芭,首先獲得它的鍵數(shù)組(對象自帶的keys()
方法)东臀,然后再通過鍵遍歷一次值就行了,很簡單犀农。
多看MDN總會有收獲惰赋!下面附上我的代碼!
var cloneObject = function(src){
var Result;
switch(Object.prototype.toString.call(src)){
case "[object Number]":
Result = (typeof src === "object"?new Number(src):parseInt(src.toString()));
break;
case "[object String]":
// 遍歷字符串 =.= 好像沒啥意義
// {
// var temp = src.split("");
// var cloneString="";
// for(var i=0;i<temp.length;i++)
// {
// cloneString+=temp[i];
// }
// }
Result = (typeof src === "object"?new String(src):src.toString());
break;
case "[object Boolean]":
Result = (typeof src === "Boolean"?new Boolean(src):src);
break;
case "[object Date]":
Result = new Date(src);
break;
case "[object Array]":
var temp = new Array();
// Array.prototype.push.apply(temp,src);
// 當使用for(var i=0,a;a = src[i++];) i會在a被賦值后就自動增加而不是
// 等到一個循環(huán)完成再增加
for(var i=0,a;a = src[i];i++)
{
// temp.push(cloneObject(a));
// 使用push方法會讓數(shù)組所有元素的類型變成undfined
temp[i] = cloneObject(a);
}
Result = temp;
delete temp;
break;
case "[object Object]":
var temp = {};
var keys = Object.keys(src);
// keys 為對象src的鍵名字數(shù)組
// 它是數(shù)組:巧凇A薇簟!
for(var i=0,a;a=keys[i];i++)
{
temp[a] = cloneObject(src[a]);
}
Result = temp;
delete temp;
delete keys;
break;
default:
break;
}
return Result;
}