原生js实现对象的克隆

简介: 原生js实现对象的克隆
   // 对象的浅克隆 作用是把一个对象克隆到另一个对象
  // 缺陷是只能克隆原始值 不能克隆引用值
  function shallowClone(origin, target) {
    // 第一步 我们需要把对象源里面的属性克隆到目标或者数组上
    var target = target || {};
    for(var prop in origin){
      // 防止克隆原型上的属性,我们在es5中有严格模式,但是为了写的代码更完美,
      // 加上这一行,克隆只能克隆该对象上面的除了原型上的属性
      if(origin.hasOwnProperty(prop)){
         target[prop] = origin[prop];       
      }
    }
    return target
  }
  var obj = {
    name: 'adf',
    age: '12',
    sex: 'male'
  }
  var obj1 = {};
  obj1 = shallowClone(obj);
  console.log(obj1);


20200206113031316.png


解析: 因为对象的浅克隆,克隆的都是原始值,当obj里面的属性值里面改变,obj1里面的值是不会改变的,因为原始值改变的是一个栈里面的值,而对象是引用值,两个对象引用的地址不一样,所以改变一个对象,另一个对象是不会改变的,如下图:


20200206112854545.png


**深度克隆**
// 深度克隆,解决浅克隆的缺陷 克隆对象,不管兑现里面的是原始值还是引用值,都克隆到另一个对象,
  // 并且改变一个对象里面的引用值,另一个对象还是不变,实现如下
  // 实现的思路如下:
  // 1.遍历源对象,拿到对象的每一个属性
  // 2.判断第一层的属性是否为原始值,如果是原始值则直接赋值
  // 3. 不是原始值则需要判单是对象还是数组,创建对应的新的对象或者数组,保证引用值使用的是自己单独的引用地址
  // 3. 递归使用deepClone 方法
  function deepClone(origin, target) {
    // 定义三个变量, 如果不传target 则使用自己定义的  
    // 判断是对象和数组有三种方法: 
    // 1. Object.prototype.toSring.call() 里面穿数组或者对象会放回不一样的字符串, 如:传入数组返回 "[object, Array]"
    // 2. A instanceof B 使用这个比比较的是 A的原型链上是否有B的原型  数组和对象两者本身都是对象类型名单上原型链上是不同的
    // 3. 使用constructor 对比的也是原型里面的构造器
    var target = target || {} ,
         toStr = Object.prototype.toString,
         isArray = "[object, Array]";
         for(var prop in origin){
          if (origin.hasOwnProperty(prop)) {
            // 因为typeof null = 'object' 所以此处需要判断是否为引用值
            if (origin[prop] !== "null" && typeof(origin[prop]) == "object") {
              // 判断当前的引用值是否为数组
                   target[prop] = (toStr.call(origin[prop] == isArray)) ? [] : {};
              // 递归
              deepClone(origin[prop], target[prop]);
            }else{
              target[prop] = origin[prop];
            }
          }
         }
         return target;
  }
  var deepObj = {
    name: 'avc',
    age: 12,
    card: ['master', 'visa'],
    son: {
      name: 'erw',
      son: {
        name: 'test'
      }
    }
  };
    var cloneObj = deepClone(deepObj);
    console.log(cloneObj)
结果如下:


20200206124117105.png


当我改变其中一个对象时候,另一个不会被改变,如下图:


20200206124222693.png


// 深度克隆 es6写法


/**
 * 克隆的方法
 * @param obj
 * @returns {*}
 */
export function cloneValue(obj) {
    if (obj instanceof Array ) {
        return cloneArray(obj);
    } else if (obj instanceof Object) {
        return cloneObj(obj)
    } else {
        return obj;
    }
}
/**
 * 克隆对象
 * @param obj
 * @returns {{}}
 */
function cloneObj(obj) {
    let res = {};
    // 获取对象里面的所有属性,包括对象里面的属性
    let objAttr = Object.getOwnPropertyNames(obj);
    for (let i = 0; i < objAttr.length; i++) {
        res[objAttr[i]] = cloneValue(obj[objAttr[i]]);
    }
    return res;
}
/**
 * 克隆数组
 * @param array
 * @returns {[]}
 */
function cloneArray(array) {
    let arr = new Array(array.length);
    for (let i = 0; i < array.length; i++) {
        arr[i] = cloneValue(array[i]);
    }
    return arr;
}


以上代码是博主个人学习用的时候写出来的,如果存在bug, 还望见谅, more interest, less interests!!!

相关文章
|
17天前
|
存储 JavaScript 索引
js开发:请解释什么是ES6的Map和Set,以及它们与普通对象和数组的区别。
ES6引入了Map和Set数据结构。Map的键可以是任意类型且有序,与对象的字符串或符号键不同;Set存储唯一值,无重复。两者皆可迭代,支持for...of循环。Map有get、set、has、delete等方法,Set有add、delete、has方法。示例展示了Map和Set的基本操作。
21 3
|
2天前
|
JavaScript 计算机视觉
原生js通过年龄判断是否可以抽奖
原生js通过年龄判断是否可以抽奖
8 0
|
3天前
|
存储 JavaScript 前端开发
原生JS如何实现验证码
原生JS如何实现验证码
9 0
|
3天前
|
JavaScript 安全 前端开发
原生JS实现一键复制,一键粘贴
原生JS实现一键复制,一键粘贴
10 0
|
4天前
|
存储 JavaScript 前端开发
JavaScript对象方法详解
JavaScript对象方法详解
13 1
|
5天前
|
JavaScript
js多维数组去重并使具有相同属性的对象数量相加
js多维数组去重并使具有相同属性的对象数量相加
10 1
|
12天前
|
前端开发 JavaScript 数据安全/隐私保护
前端javascript的DOM对象操作技巧,全场景解析(二)
前端javascript的DOM对象操作技巧,全场景解析(二)
|
12天前
|
移动开发 缓存 JavaScript
前端javascript的DOM对象操作技巧,全场景解析(一)
前端javascript的DOM对象操作技巧,全场景解析(一)
|
12天前
|
缓存 编解码 自然语言处理
前端javascript的BOM对象知识精讲
前端javascript的BOM对象知识精讲
|
12天前
|
JavaScript 前端开发
JavaScript 日期对象
JavaScript 日期对象