前言:眾所周知JavaScript 里邊的數(shù)據(jù)類型大的分為:基本數(shù)據(jù)類型和引用數(shù)據(jù)類型屋谭。咱們今天說的對象拷貝就屬于引用數(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è)引用(地址)。那如何避免這樣的問題呢?這就要提到咱們今天的重點(diǎn)了對象的拷貝
對象的拷貝
對象的拷貝又分為淺拷貝和深拷貝。深淺就說明了對象拷貝的層級(jí)。淺拷貝只拷貝第一層級(jí)睬愤,但深拷貝拷貝整個(gè)對象的所有層級(jí)。下面呢纹安,咱們就用代碼來展示一下淺拷貝尤辱。
淺拷貝
先介紹一下里邊用到的一些代碼(代碼解析)
-
Object.prototype.toString.call(target);
每個(gè)對象都有一個(gè) toString() 方法,當(dāng)該對象被表示為一個(gè)文本值時(shí)钻蔑,或者一個(gè)對象以預(yù)期的字符串方式引用時(shí)自動(dòng)調(diào)用啥刻。默認(rèn)情況下,toString() 方法被每個(gè) Object 對象繼承咪笑。如果此方法在自定義對象中未被覆蓋可帽,toString() 返回 "[object type]",其中 type 是對象的類型窗怒。
這主要是用于區(qū)分對象與數(shù)組映跟,在JavaScript中數(shù)組也屬于對象,所以用
typeof
是無法區(qū)分是對象還是數(shù)組扬虚。
對象[object Object]
數(shù)組[object Array]
Object.hasOwnProperty.call(target, key)
對象本身是否含有該屬性努隙,不會(huì)查找原型鏈上的東西Array.prototype.slice.call(target)
返回一個(gè)新數(shù)組
/**
* 對象拷貝
* @param {*} target 目標(biāo)對象
* @returns new Object
*/
function clone(target) {
const type = Object.prototype.toString.call(target);
if (type === "[object Object]") {
// 代表這是一個(gè)對象
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)了,淺拷貝都是僅僅拷貝了對象的第一層辜昵。而深拷貝呢就針對對象的所有層級(jí)進(jìn)行操作荸镊。來看下邊代碼。
深拷貝
先介紹一下里邊用到的一些代碼(代碼解析)
- arguments.callee
指向當(dāng)前函數(shù)的引用
/**
* 對象深拷貝
* @param {*} target 目標(biāo)對象
* @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è)對象
const tempObj = {};
for (const key in target) {
if (Object.hasOwnProperty.call(target, key)) {
// 深拷貝 不僅僅是針對對象第一次堪置,而是采用遞歸的方式逐個(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ā)中用的代碼
/**
* 對象拷貝
* @param {*} target 目標(biāo)對象
* @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è)對象
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);
}
}
}
}
好了躬存,針對對象的深淺拷貝的解析今天就到這了,謝謝欣賞舀锨。