????javascript的基本類型包括字符串强法、數(shù)字万俗、布爾、數(shù)組饮怯、對象闰歪、Null、Undefined硕淑】慰ⅲ基本類型和對象最大的不同在于他們的傳值方式:基本類型是按值傳遞的嘉赎,但是對象是按引用傳值的.
基本類型:
var a = 1;
var b = a;
b = 2;
console.log(a); //1
console.log(b); //2
從上面的例子可以看出置媳,由于是按值傳遞,所以改變b的值不會(huì)改變a
如果是對象公条,由于是按引用傳值拇囊,類似的做法會(huì)改變另外一個(gè)相關(guān)對象的屬性,這就是淺復(fù)制(新舊對象公用一塊內(nèi)存空間):
var obj1 = { a:1 , b:2 };
var obj2 = obj1;
obj.a = 3;
console.log(obj1); //{ a:3 , b:2 }
console.log(obj2); //{ a:3 , b:2 }
console.log(obj1 === obj2); //true
如果不讓原本obj1對象屬性靶橱,那么就是深復(fù)制(新舊對象使用不同內(nèi)存空間)
簡單實(shí)現(xiàn):
var obj2 = { a:obj1.a , b:obj1.b };
obj2.a = 3;
console.log(obj1); //{ a:1 , b:2 }
console.log(obj2); //{ a:3 , b:2 }
console.log(obj1 === obj2); //false
這種方法可以實(shí)現(xiàn)深度復(fù)制寥袭,但是略顯臃腫,而且如果有嵌套對象(有多層對象)實(shí)現(xiàn)起來就更麻煩了关霸,比如:
var obj1 = { grade : { math : 100 , Chinese : 90 } };
var obj2 = { grade : obj1.grade };
obj2.grade.math = 120;
console.log(obj1); // { grade : { math : 120 , Chinese : 90 } };
var obj2 = { grade : obj1.grade.math , grade : obj1.grade.Chinese }; //這樣才能深度復(fù)制
深度復(fù)制除了上面方法传黄,還可以用其他方法實(shí)現(xiàn)
1.ES6的Object.assign
ES6引入了一個(gè)Object.assign的新函數(shù),可以把任意個(gè)源對象自身的可枚舉屬性拷貝給目標(biāo)對象队寇,然后再返回目標(biāo)對象膘掰。不過其進(jìn)行的是淺復(fù)制i,復(fù)制的是對象屬性的引用
不過佳遣,它還是可以實(shí)現(xiàn)一層的深度復(fù)制识埋,比起前面的手動(dòng)復(fù)制要簡單一點(diǎn),比如
var obj1 = { a:1 , b:2 };
var obj2 = Object.assign( {} , obj1 };
obj.a = 3;
console.log(obj1); //{ a:1 , b:2 }
console.log(obj2); //{ a:3 , b:2 }
2.JSON.stringify+JSON.parse
前面提到了零渐,js的基本類型是按值傳遞的窒舟,那么既然有這樣的特性我們完全可以將對象轉(zhuǎn)換成字符串,然后再用parse解析成新對象
var obj1 = { a:1 , b:2 };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj.a = 3;
console.log(obj1); //{ a:1 , b:2 }
console.log(obj2); //{ a:3 , b:2 }
console.log(obj1 === obj2); //false
不過诵盼,這個(gè)方法還是有缺陷惠豺,只有可以轉(zhuǎn)換成JSON格式的對象才可以使用,RegExp對象是無法通過該方法實(shí)現(xiàn)深度復(fù)制的风宁,函數(shù)也無法使用
3.遞歸拷貝
function deepClone(initalObj,finalObj){
var obj = finalObj || {};
for(var i in initalObj){
var prop = initalObj[i];
if(prop === obj)
continue;
if(typeof prop === 'object'){
obj[i] = (prop.constructor === Array) ? [] : {};
arguments.callee(prop,obj[i]);
}else{
obj[i] = prop;
}
}
return obj;
}
4.Object.create(initalObj)
注意和前面遞歸方法的區(qū)別
function deepClone(initalObj,finalObj){
var obj = finalObj || {};
for(var i in initalObj){
var prop = initalObj[i];
if(prop === obj)
continue;
if(typeof prop === 'object'){
obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
arguments.callee(prop,obj[i]);
}else{
obj[i] = prop;
}
}
return obj;
}
5.slice和concat巧妙的方法
實(shí)質(zhì)上這也是淺復(fù)制耕腾,只不過返回一個(gè)淺復(fù)制了原數(shù)組中的元素的一個(gè)新數(shù)組
var arr1 = [1, 2, 3, 4],
arr2 = arr1.slice(0),
arr3 = arr1.concat();
console.log(arr1, arr2, arr3);
arr2[2] = 10;
arr3[2] = 11;
console.log(arr1[2], arr2[2], arr3[2]);
> 1,2,3,4, 1,2,3,4, 1,2,3,4
> 3, 10, 11
console.log( arr1 === arr2 ); //false
console.log( arr1 === arr3 ); //false
又比如:
var array = [1, [1,2,3], {name:"array"}];
var array_concat = array.concat();
var array_slice = array.slice(0);
array_concat[1][0] = 5; //改變array_concat中數(shù)組元素的值
console.log(array[1]); //[5,2,3]
console.log(array_slice[1]); //[5,2,3]
array_slice[2].name = "array_slice"; //改變array_slice中對象元素的值
console.log(array[2].name); //array_slice
console.log(array_concat[2].name); //array_slice
jQuery提供了一個(gè)$.extend方法可以做深度復(fù)制
var arr1 = [1, 2, [3, 4], {a: 5, b: 6}, 7],
arr2 = $.extend(true, [], arr1);
console.log(arr1, arr2);
arr2[1] = 10;
console.log(arr1, arr2);
還有一個(gè)叫l(wèi)odash的函數(shù)庫的_.cloneDeep方法可以實(shí)現(xiàn)深度復(fù)制
參考:http://www.cnblogs.com/Chen-XiaoJun/p/6217373.html
http://web.jobbole.com/88602/
https://github.com/wengjq/Blog/issues/3