JavaScript之對(duì)象的拷貝

前言:眾所周知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ì)象的深淺拷貝的解析今天就到這了,謝謝欣賞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容