原生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!!!

相关文章
|
JavaScript 前端开发
如何在 JavaScript 中使用 __proto__ 实现对象的继承?
使用`__proto__`实现对象继承时需要注意原型链的完整性和属性方法的正确继承,避免出现意外的行为和错误。同时,在现代JavaScript中,也可以使用`class`和`extends`关键字来实现更简洁和直观的继承语法,但理解基于`__proto__`的继承方式对于深入理解JavaScript的面向对象编程和原型链机制仍然具有重要意义。
|
Web App开发 JavaScript 前端开发
如何确保 Math 对象的方法在不同的 JavaScript 环境中具有一致的精度?
【10月更文挑战第29天】通过遵循标准和最佳实践、采用固定精度计算、进行全面的测试与验证、避免隐式类型转换以及持续关注和更新等方法,可以在很大程度上确保Math对象的方法在不同的JavaScript环境中具有一致的精度,从而提高代码的可靠性和可移植性。
|
编解码 JavaScript 前端开发
【Java进阶】详解JavaScript的BOM(浏览器对象模型)
总的来说,BOM提供了一种方式来与浏览器进行交互。通过BOM,你可以操作窗口、获取URL、操作历史、访问HTML文档、获取浏览器信息和屏幕信息等。虽然BOM并没有正式的标准,但大多数现代浏览器都实现了相似的功能,因此,你可以放心地在你的JavaScript代码中使用BOM。
514 23
|
JSON 前端开发 JavaScript
JavaScript中对象的数据拷贝
本文介绍了JavaScript中对象数据拷贝的问题及解决方案。作者首先解释了对象赋值时地址共享导致的值同步变化现象,随后提供了五种解决方法:手动复制、`Object.assign`、扩展运算符、`JSON.stringify`与`JSON.parse`组合以及自定义深拷贝函数。每种方法都有其适用场景和局限性,文章最后鼓励读者关注作者以获取更多前端知识分享。
408 1
JavaScript中对象的数据拷贝
|
JavaScript 前端开发 测试技术
盘点原生JavaScript中直接触发事件的方式
本文全面探讨了原生JavaScript中触发事件的多种方式,包括`dispatchEvent`、`Event`构造函数、`CustomEvent`构造器、直接调用事件处理器以及过时的`createEvent`和`initEvent`方法。通过技术案例分析,如模拟点击事件、派发自定义数据加载事件和实现提示框系统,帮助开发者掌握这些方法在实际开发中的应用,提升灵活性与兼容性。
699 3
|
JavaScript 前端开发 图形学
JavaScript 中 Math 对象常用方法
【10月更文挑战第29天】JavaScript中的Math对象提供了丰富多样的数学方法,涵盖了基本数学运算、幂运算、开方、随机数生成、极值获取以及三角函数等多个方面,为各种数学相关的计算和处理提供了强大的支持,是JavaScript编程中不可或缺的一部分。
|
存储 JavaScript 前端开发
JavaScript 对象的概念
JavaScript 对象的概念
283 4
|
存储 JavaScript 前端开发
js中函数、方法、对象的区别
js中函数、方法、对象的区别
551 2
|
JavaScript 前端开发 Unix
Node.js 全局对象
10月更文挑战第5天
296 2
|
存储 JavaScript 前端开发
js中的对象
js中的对象
204 3