前言:眾所周知JavaScript 里邊的數(shù)據(jù)類型大的分為:基本數(shù)據(jù)類型和引用數(shù)據(jù)類型。咱們今天說(shuō)的對(duì)象拷貝就屬于引用數(shù)據(jù)類型里的東西。哪基本數(shù)據(jù)類型和引用數(shù)據(jù)類型之間又啥區(qū)別呢?
基本數(shù)據(jù)類型和引用數(shù)據(jù)類型的區(qū)別
基本數(shù)據(jù)類型存儲(chǔ)的是數(shù)據(jù)
引用數(shù)據(jù)類型存儲(chǔ)的是數(shù)據(jù)的地址(引用)
這就是他們之前的區(qū)別
舉個(gè)栗子
var user = {
name: "張三",
age: 18,
address: {
city: "大連"
},
cards: [
{
num: "6240**",
name: "招商銀行"
}
]
};
var user2 = user;
user2.address.city = "湖北";
console.log(user.address.city === user2.address.city) // ?
結(jié)果是 true,原因就是他們指向同一個(gè)引用(地址)。那如何避免這樣的問(wèn)題呢?這就要提到咱們今天的重點(diǎn)了對(duì)象的拷貝
對(duì)象的拷貝
對(duì)象的拷貝又分為淺拷貝和深拷貝。深淺就說(shuō)明了對(duì)象拷貝的層級(jí)。淺拷貝只拷貝第一層級(jí),但深拷貝拷貝整個(gè)對(duì)象的所有層級(jí)。下面呢,咱們就用代碼來(lái)展示一下淺拷貝。
淺拷貝
先介紹一下里邊用到的一些代碼(代碼解析)
-
Object.prototype.toString.call(target);
每個(gè)對(duì)象都有一個(gè) toString() 方法,當(dāng)該對(duì)象被表示為一個(gè)文本值時(shí),或者一個(gè)對(duì)象以預(yù)期的字符串方式引用時(shí)自動(dòng)調(diào)用。默認(rèn)情況下,toString() 方法被每個(gè) Object 對(duì)象繼承。如果此方法在自定義對(duì)象中未被覆蓋,toString() 返回 "[object type]",其中 type 是對(duì)象的類型。
這主要是用于區(qū)分對(duì)象與數(shù)組,在JavaScript中數(shù)組也屬于對(duì)象,所以用
typeof是無(wú)法區(qū)分是對(duì)象還是數(shù)組。
對(duì)象[object Object]
數(shù)組[object Array] Object.hasOwnProperty.call(target, key)
對(duì)象本身是否含有該屬性,不會(huì)查找原型鏈上的東西Array.prototype.slice.call(target)
返回一個(gè)新數(shù)組
/**
* 對(duì)象拷貝
* @param {*} target 目標(biāo)對(duì)象
* @returns new Object
*/
function clone(target) {
const type = Object.prototype.toString.call(target);
if (type === "[object Object]") {
// 代表這是一個(gè)對(duì)象
const tempObj = {};
for (const key in target) {
if (Object.hasOwnProperty.call(target, key)) {
// 拷貝
tempObj[key] = target[key];
}
}
return tempObj;
} else if (type === "[object Array]") {
// 代表這是一個(gè)數(shù)組
return Array.prototype.slice.call(target);
}
}
眼細(xì)的同學(xué)就發(fā)現(xiàn)了,淺拷貝都是僅僅拷貝了對(duì)象的第一層。而深拷貝呢就針對(duì)對(duì)象的所有層級(jí)進(jìn)行操作。來(lái)看下邊代碼。
深拷貝
先介紹一下里邊用到的一些代碼(代碼解析)
- arguments.callee
指向當(dāng)前函數(shù)的引用
/**
* 對(duì)象深拷貝
* @param {*} target 目標(biāo)對(duì)象
* @returns new Object
*/
function clone(target) {
if (typeof target !== "object") {
return target;
} else {
const type = Object.prototype.toString.call(target);
if (type === "[object Object]") {
// 代表這是一個(gè)對(duì)象
const tempObj = {};
for (const key in target) {
if (Object.hasOwnProperty.call(target, key)) {
// 深拷貝 不僅僅是針對(duì)對(duì)象第一次,而是采用遞歸的方式逐個(gè)拷貝
tempObj[key] = arguments.callee(target[key]);
}
}
return tempObj;
} else if (type === "[object Array]") {
// 代表這是一個(gè)數(shù)組
const newArr = [];
target.forEach(element => {
newArr.push(arguments.callee(element));
});
return newArr;
}
}
}
開發(fā)中用的代碼
/**
* 對(duì)象拷貝
* @param {*} target 目標(biāo)對(duì)象
* @param {*} deep 是否開啟深拷貝默認(rèn)為false
* @returns new Object
*/
function clone(target, deep) {
if (typeof target !== "object") {
return target;
} else {
const type = Object.prototype.toString.call(target);
if (type === "[object Object]") {
// 代表這是一個(gè)對(duì)象
const tempObj = {};
for (const key in target) {
if (Object.hasOwnProperty.call(target, key)) {
if (deep) {
// 深拷貝
tempObj[key] = arguments.callee(target[key], deep);
} else {
// 淺拷貝
tempObj[key] = target[key];
}
}
}
return tempObj;
} else if (type === "[object Array]") {
// 代表這是一個(gè)數(shù)組
if (deep) {
const newArr = [];
target.forEach(element => {
newArr.push(arguments.callee(element, deep));
});
return newArr;
} else {
return Array.prototype.slice.call(target);
}
}
}
}
好了,針對(duì)對(duì)象的深淺拷貝的解析今天就到這了,謝謝欣賞。