深拷貝與淺拷貝
基本類型的拷貝
先來看一段非常經(jīng)典的代碼
var a = 1;
var b = a;
a = 200;
console.log(a); //200
console.log(b); //1
我們應(yīng)該知道基本類型“按值傳遞”,引用類型“按引用傳遞”,數(shù)值作為基本類型是保存在棧內(nèi)存中,可以直接拿來用的,賦值是什么那么之后就一直是什么,不會(huì)受到傳遞元素的改變帶來的影響,所以這里就不難理解上面的代碼得到的值的原因了。
引用類型的拷貝
簡(jiǎn)單說,引用類型是生成一個(gè)指針保存的堆內(nèi)存中,當(dāng)給引用類型賦值時(shí),我們寫的內(nèi)容是在棧內(nèi)存中,也就是說我們拿到的其實(shí)是一個(gè)指針(不會(huì)直接拿到棧內(nèi)存中的內(nèi)容)。這個(gè)指針是指向棧內(nèi)存中這個(gè)引用類型的代碼。
淺拷貝針對(duì)對(duì)象中的基本類型的值生效,但是對(duì)引用類型中還有引用類型的情況就會(huì)失效。
所謂的深淺拷貝是相對(duì)與typeof === 'object' 而言的,數(shù)組是用堆對(duì)應(yīng)保存的。
淺拷貝:拷貝了對(duì)象的存放地址,只是指向相同而已 (只解決了第一層,對(duì)象中還有對(duì)象就不適用了)
深拷貝:完全復(fù)制了一個(gè)獨(dú)立的個(gè)體
- 淺拷貝方法:(直接 =,Object.assign...大部分都是淺拷貝)
=
let arr1 = [1,3,5];
let arr2 = arr1;
arr1[0] = 10;
console.log(arr2) // [10,3,5]
var obj1 = {
name: '張三'
}
var obj2 = obj1;
obj2.name = '李四';
console.log(obj1.name); // '李四'
Object.assign
var obj1 = {
name: '張三'
}
var obj2 = Object.assign({}, obj1);
obj2.name = '李四';
console.log(obj1.name); // '張三'
至此,淺拷貝成功,但存在兼容性問題,比如低端的安卓機(jī)等,這個(gè)需要注意。但細(xì)心的朋友肯定會(huì)再做一個(gè)測(cè)試,如下:
var obj1 = {
name: '張三',
friends: {
name: '劉備',
age: 33
}
}
var obj2 = Object.assign({}, obj1);
obj2.name = '李四';
obj2.friends.name = '關(guān)羽';
console.log(obj1.name); // '張三'
console.log(obj1.friends.name); // '關(guān)羽'
是的,到這一步,我們失敗了,對(duì)象中嵌套對(duì)象時(shí),Object.assign()只能拷貝一層,那如何解決呢?其實(shí)就要用到深拷貝的方法了:
var obj1 = {
name: '張三',
friends: {
name: '劉備',
age: 33
}
}
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = '李四';
obj2.friends.name = '關(guān)羽';
console.log(obj1.name); // '張三'
console.log(obj1.friends.name); // '劉備'
- 深拷貝方法:
Json.parse(Json.stringify())
var obj1 = {
name: '張三',
friends: {
name: '劉備',
age: 33
}
}
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = '李四';
obj2.friends.name = '關(guān)羽';
console.log(obj1.name); // '張三'
console.log(obj1.friends.name); // '劉備'
$.extend
...運(yùn)算符
let arr = [1,3,5];
let arr1 = [...arr];
返回新數(shù)組方法 slice() 、 contat()、 map()
let arr1 = [2,5,7];
let arr2 = arr1.slice(0);
let arr3 = arr1.contat();
let arr4 = arr1.map(x => x);
arr2[0] = 4;
arr1[0] = 99;
console.log(arr1,arr2) // [99,5,7] [4,5,7]
for-in連原型鏈也一并復(fù)制的方法
let arr = [1,3,5];
let arr2 = [] ;
for(var key in arr) {
arr2[key] = arr[key]
}
封裝方法
/**
* 判斷對(duì)象類型
* @param {Object} object
* @return {String} object type
*/
getType(object) {
var toString = Object.prototype.toString;
var map = {
'[object Boolean]': 'boolean',
'[object Number]': 'number',
'[object String]': 'string',
'[object Function]': 'function',
'[object Array]': 'array',
'[object Date]': 'date',
'[object RegExp]': 'regExp',
'[object Undefined]': 'undefined',
'[object Null]': 'null',
'[object Object]': 'object'
};
if (object instanceof Element) {
return 'element';
}
return map[toString.call(object)];
},
/**
* 對(duì)象的深度拷貝
* @param data 需要拷貝的元數(shù)據(jù)
* @return {any} 返回拷貝后的新數(shù)據(jù)
*/
deepClone(data) {
const type = this.getType(data);
let obj;
if (type === 'array') {
obj = [];
} else if (type === 'object') {
obj = {};
} else {
//不再具有下一層次
return data;
}
if (type === 'array') {
for (let i = 0, len = data.length; i < len; i++) {
obj.push(this.deepClone(data[i]));
}
} else if (type === 'object') {
for (let key in data) {
obj[key] = this.deepClone(data[key]);
}
}
const constructor = data.constructor;
if (constructor) {
return Object.assign(new constructor(), obj);
}
return obj;
},