美文网首页
JavaScript之对象的拷贝

JavaScript之对象的拷贝

作者: jw_fc89 | 来源:发表于2021-12-21 11:02 被阅读0次

    前言:众所周知JavaScript 里边的数据类型大的分为:基本数据类型和引用数据类型。咱们今天说的对象拷贝就属于引用数据类型里的东西。哪基本数据类型和引用数据类型之间又啥区别呢?

    基本数据类型和引用数据类型的区别

    基本数据类型存储的是数据
    引用数据类型存储的是数据的地址(引用)
    这就是他们之前的区别
    举个栗子

    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) // ?
    

    结果是 true,原因就是他们指向同一个引用(地址)。那如何避免这样的问题呢?这就要提到咱们今天的重点了对象的拷贝

    对象的拷贝

    对象的拷贝又分为浅拷贝和深拷贝。深浅就说明了对象拷贝的层级。浅拷贝只拷贝第一层级,但深拷贝拷贝整个对象的所有层级。下面呢,咱们就用代码来展示一下浅拷贝。

    浅拷贝

    先介绍一下里边用到的一些代码(代码解析)

    • Object.prototype.toString.call(target);

      每个对象都有一个 toString() 方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。默认情况下,toString() 方法被每个 Object 对象继承。如果此方法在自定义对象中未被覆盖,toString() 返回 "[object type]",其中 type 是对象的类型。

      这主要是用于区分对象与数组,在JavaScript中数组也属于对象,所以用typeof是无法区分是对象还是数组。
      对象 [object Object]
      数组 [object Array]

    • Object.hasOwnProperty.call(target, key)
      对象本身是否含有该属性,不会查找原型链上的东西

    • Array.prototype.slice.call(target)
      返回一个新数组

    /**
     * 对象拷贝
     * @param {*} target 目标对象
     * @returns new Object
     */
    function clone(target) {
        const type = Object.prototype.toString.call(target);
        if (type === "[object Object]") {
            // 代表这是一个对象
            const tempObj = {};
            for (const key in target) {
                if (Object.hasOwnProperty.call(target, key)) {
                    // 拷贝
                    tempObj[key] = target[key];
                }
            }
            return tempObj;
        } else if (type === "[object Array]") {
            // 代表这是一个数组
            return Array.prototype.slice.call(target);
        }
    }
    

    眼细的同学就发现了,浅拷贝都是仅仅拷贝了对象的第一层。而深拷贝呢就针对对象的所有层级进行操作。来看下边代码。

    深拷贝

    先介绍一下里边用到的一些代码(代码解析)

    • arguments.callee
      指向当前函数的引用
    /**
     * 对象深拷贝
     * @param {*} target 目标对象
     * @returns new Object
     */
    function clone(target) {
        if (typeof target !== "object") {
            return target;
        } else {
            const type = Object.prototype.toString.call(target);
            if (type === "[object Object]") {
                // 代表这是一个对象
                const tempObj = {};
                for (const key in target) {
                    if (Object.hasOwnProperty.call(target, key)) {
                        // 深拷贝 不仅仅是针对对象第一次,而是采用递归的方式逐个拷贝
                        tempObj[key] = arguments.callee(target[key]);
                    }
                }
                return tempObj;
            } else if (type === "[object Array]") {
                // 代表这是一个数组
                const newArr = [];
                target.forEach(element => {
                    newArr.push(arguments.callee(element));
                });
                return newArr;
            }
        }
    }
    

    开发中用的代码

    /**
     * 对象拷贝
     * @param {*} target 目标对象
     * @param {*} deep 是否开启深拷贝默认为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]") {
                // 代表这是一个对象
                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]") {
                // 代表这是一个数组
                if (deep) {
                    const newArr = [];
                    target.forEach(element => {
                        newArr.push(arguments.callee(element, deep));
                    });
                    return newArr;
                } else {
                    return Array.prototype.slice.call(target);
                }
            }
        }
    }
    

    好了,针对对象的深浅拷贝的解析今天就到这了,谢谢欣赏。

    相关文章

      网友评论

          本文标题:JavaScript之对象的拷贝

          本文链接:https://www.haomeiwen.com/subject/wkotqrtx.html