js 实现对象的混合与克隆效果,带完整版解析代码

女生的网名这么多〃 提交于 2020-04-04 09:34:22

前言:

        本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽。

        本篇文章为您分析一下原生JS写对象混合与克隆

对象混合

页面中如下需求

var obj1 = {
    x: 1,
    y: "a"
}

var obj2 = {
    x: "b",
    o: 6
}


页面上有两个对象
我们要把这两个对象混合成一个
形成如下结构:

// 将obj2混合到obj1中
obj = { 
    x: "b",
    y: "a",
    o: 6
    }


参考代码:

    // ES5之前的版本
    function mixin(obj1, obj2){
        // 第一步: 创建一个对象
        var newObj = {};
        // 第二步: 循环obj2中的对象
        for(var prop in obj2){
            // 第三步: 将obj2中的属性添加到新创建爱对象中
            newObj[prop] = obj2[prop];
        }
        // 第四步: 循环obj1中的对象
        for(var prop in obj1){
            // 第五步: 看看obj1中的属性在不在obj2中,如果不在就将他加入的新的对象中
            if(!(prop in obj2)){
                newObj[prop] = obj1[prop];
            }
        }
        // 最后返回这个新的对象
        return newObj;
    }


    // ES6版本
    // function mixin(obj1, obj2){
    //     return Object.assgin({},obj1,obj2);
    // }
 
  

在页面中调用

        var obj = mixin(obj1, obj2);
        console.log(obj);

图片

对象克隆

页面中如下需求
        var obj = {
            x: "123",
            y: 456,
            objSon: {
                c: "a"
            }
        }

        var newObj = clone(obj);
        //  要求实现newObj中有obj的所有属性
        //  并且newObj.objSon !== obj.objSon;


下面来看看代码

        function clone(obj) {
            var newObj = {};
            for (var prop in obj) {
                newObj[prop] = obj[prop];
            }
        }


下面来看看效果

图片


如果obj是一个数字会怎么样呢?
var obj = 123;

图片


为什么会是一个对象呢?
因为我们在function中创建了一个对象
如果obj是一个字符串呢? var obj = "abcdefg";

图片


如果obj是一个数组又会怎么样呢?
var obj = [12,35,65,87,1,3];

图片


他克隆出来就是一个伪数组了
而且length属性还得不到

图片


鉴于上面出现的多种情况
我们刚刚写的代码(只是假设他是普通对象,还不是数组对象,数组本身也是对象嘛)就不足以完成一个完整的克隆函数
因此,我们要进行判断

        function clone(obj) {
            if (Array.isArray(obj)) {  // 如果他是一个数组
                return obj.slice();    // 复制数组
            } else if (typeof obj === "object") {  // 如果他是一个普通对象
                var newObj = {};       // 定义一个对象
                for (var prop in obj) {  // 循环obj
                    newObj[prop] = obj[prop];  // 添加属性
                }
                return newObj;         // 返回
            } else {                   // 函数、原始类型
                return obj;            // 直接返回
            }
        }



在页面上打印newObj

图片 判断newObj === obj


现在来看这个克隆更加优化了
但是并没有完整
如果obj的属性也是一个对象呢?

        var obj = {
            x: "123",
            y: 456,
            subObj: {
                a: "abc"
            }
        }


newObj本身是不等于obj的,因为是克隆嘛,产生了一个新的对象
但是它里面的subObj属性的地址是一样的
如果我们给newObj.subObj.a ==="XXX";赋值了。
他会导致:obj.subObj.a也跟着改变。
所以我们把目前我们写的这种方式叫做 [浅度克隆]
还有一种克隆叫 [深度克隆] 就是要对他属性做深度处理
因此这个函数还需要一个参数来判断他是否需要深度克隆

        function clone(obj, deep) {
            if (Array.isArray(obj)) {  // 如果他是一个数组
                return obj.slice();    // 复制数组
            } else if (typeof obj === "object") {  // 如果他是一个普通对象
                var newObj = {};       // 定义一个对象
                for (var prop in obj) {  // 循环obj
                    if (deep){
                        // 如果是深度克隆的话,我们把这个属性的值再克隆一遍【递归】
                        newObj[prop] = this.clone(obj[prop], deep);
                    }else {
                        newObj[prop] = obj[prop];  // 添加属性
                    }
                }
                return newObj;         // 返回
            } else {                   // 函数、原始类型
                return obj;            // 直接返回 【递归的终止条件】
            }
        }

        // 再传入第二个参数  
        var newObj = clone(obj, true);

图片 newObj。subObj' ===


针对数组如何深度克隆

        function clone(obj, deep) {
            if (Array.isArray(obj)) {  // 如果他是一个数组
            if(deep){  // 深度克隆
                var newArr = [];  //定义一个空数组
                for(var i = 0; i< obj.length; i++){ // 循环obj的每一项
                    newArr[i].push(clone(obj[i],deep)); // pun数组
                } 
            }else {
                return obj.slice();    // 复制数组
            }
                
            } else if (typeof obj === "object") {  // 如果他是一个普通对象
                var newObj = {};       // 定义一个对象
                for (var prop in obj) {  // 循环obj
                    if (deep){
                        // 如果是深度克隆的话,我们把这个属性的值再克隆一遍【递归】
                        newObj[prop] = this.clone(obj[prop], deep);
                    }else {
                        newObj[prop] = obj[prop];  // 添加属性
                    }
                }
                return newObj;         // 返回
            } else {                   // 函数、原始类型
                return obj;            // 直接返回 【递归的终止条件】
            }
        }

图片


这样就完成了对象的克隆

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!