/* ===================== 直接看代码 ===================== */
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <h1>http://www.codeceo.com/article/javascript-object-deep-copy.html</h1>
  <p>
    对象的深拷贝与浅拷贝的区别如下:
    浅拷贝:仅仅复制对象的引用,而不是对象本身;
    深拷贝:把复制的对象所引用的全部对象都复制一遍。
  </p>
  一. 浅拷贝的实现
<script type="text/javascript">
  Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象 (简单粗暴明了 推荐首选)
  详情直戳 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
  function test() {
  'use strict';   let obj1 = { a: 0 , b: { c: 0}};
  let obj2 = Object.assign({}, obj1);
  console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}   obj1.a = 1;
  console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
  console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}    obj2.a = 2;
   console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
  console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}   obj2.b.c = 3;
  console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}
  console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}}   // Deep Clone
  obj1 = { a: 0 , b: { c: 0}};
  let obj3 = JSON.parse(JSON.stringify(obj1));
   obj1.a = 4;
  obj1.b.c = 4;
  console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}   // 拷贝单个对象
  var obj = { a: 1 };
   var copy = Object.assign({}, obj);
  console.log(copy); // { a: 1 }   // 合并多个对象
  let o1 = { a: 1 };
  let o2 = { b: 2 };
  let o3 = { c: 3 };   let obj = Object.assign(o1, o2, o3);
  console.log(obj); // { a: 1, b: 2, c: 3 }
  console.log(o1); // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变
  }   // 需要注意的是浅拷贝的话当自身或者目标对象改变两者皆会改变 (希望不改变则需要深拷贝)
  test();

</script>
<script type="text/javascript">
  二. 深拷贝的实现

  要实现深拷贝有很多办法,有最简单的 JSON.parse() 方法,也有常用的递归拷贝方法,和ES5中的 Object.create() 方法。
  2.1 方法一:使用 JSON.parse() 方法
  要实现深拷贝有很多办法,比如最简单的办法是使用 JSON.parse():
  function deepClone(initalObj) {
  var obj = {};
  try {
   obj = JSON.parse(JSON.stringify(initalObj));
  }
   return obj;
  }
  var obj = {
  a: {
  a: "world",
  b: 21
  }
  }
  var cloneObj = deepClone(obj);
  cloneObj.a.a = "changed";
  console.log(obj.a.a); // "world"
  这种方法简单易用。
  但是这种方法也有不少坏处,譬如它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。
  这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,即那些能够被 json 直接表示的数据结构。RegExp对象是无法通过这种方式深拷贝。
  2.2 方法二:递归拷贝
  为了避免相互引用的对象导致死循环的情况,则应该在遍历的时候判断是否相互引用对象,如果是则退出循环。
  版代码如下:
 // 深拷贝 递归1.1 写法一
  function deepClone(obj) {
  var obj = {};
  for (var i in initalObj) {
  var prop = initalObj[i];
  // 避免相互引用对象导致死循环,
  if(prop === obj) {
  continue;
   }
  if (typeof prop === 'object') {
   obj[i] = (prop.constructor === Array) ? [] : {};
   arguments.callee(prop, obj[i]);
  } else {
  obj[i] = prop;
  }
   }
  return obj;
  }
 
// 深拷贝 递归1.2 写法二
function deepCopy(p, c) {
  var c = c || {};
  for (var i in p) {
    if (typeof p[i] === 'object') {
      c[i] = (p[i].constructor === Array) ? [] : {};
      deepCopy(p[i], c[i]);
    } else {
       c[i] = p[i];
    }
  }
  return c;
}

  
 // 深拷贝 递归1.3 写法二  比较全面的写法 参考至 (https://mp.weixin.qq.com/s/vXbFsG59L1Ba0DMcZeU2Bg
  function forEach(array, cloneTarget) {
let index = -;
const length = array.length;
while (++index < length) {
cloneTarget(array[index], index);
}
return array;
} function clone(target, map = new WeakMap()) {
if (typeof target === 'object') {
const isArray = Array.isArray(target);
let cloneTarget = isArray ? [] : {};
if (map.get(target)) {
return target;
}
map.set(target, cloneTarget);
const keys = isArray ? undefined : Object.keys(target);
forEach(keys || target, (value, key) => {
if (keys) key = value
cloneTarget[key] = clone(target[key], map);
});
return cloneTarget;
} else {
return target;
}
}
  2.3 方法三:集合Object.assign()方法
  // 深拷贝
  function deepClone(initalObj) {
  var obj = {};
  for (var i in initalObj) {
  var prop = initalObj[i];
  // 避免相互引用对象导致死循环
  if(prop === obj) {
   continue;
  }
  if (typeof prop === 'object') {
  obj[i] = Object.assign(prop);
   } else {
  obj[i] = prop;
  }
  }
  return obj;
  }
</script>
</body>
</html>

有问题或者有bug非常欢迎留言指正。

深拷贝1.3版本参考至: https://mp.weixin.qq.com/s/vXbFsG59L1Ba0DMcZeU2Bg  (递归方法总结的很全面推荐)

Object对象的浅拷贝与深拷贝方法详解的更多相关文章

  1. 并发编程(六)Object类中线程相关的方法详解

    一.notify() 作用:唤醒一个正在等待该线程的锁的线程 PS : 唤醒的线程不会立即执行,它会与其他线程一起,争夺资源 /** * Object类的notify()和notifyAll()方法详 ...

  2. java数组、java.lang.String、java.util.Arrays、java.lang.Object的toString()方法和equals()方法详解

    public class Test { public static void main(String[] args) { int[] a = {1, 2, 4, 6}; int[] b = a; in ...

  3. 深拷贝与浅拷贝(mutableCopy与Copy)详解 iOS

    深拷贝与浅拷贝(mutableCopy与Copy)详解 iOS ios中并不是所有的对象都支持copy,mutableCopy,遵守NSCopying 协议的类可以发送copy消息,遵守NSMutab ...

  4. 用Newtonsoft将json串转为对象的方法(详解)

    首先,将json串转为一个JObject对象: JObject jo = (JObject)JsonConvert.DeserializeObject(CurrentSelectedItemReq) ...

  5. Python学习之旅—生成器对象的send方法详解

    前言 在上一篇博客中,笔者带大家一起探讨了生成器与迭代器的本质原理和使用,本次博客将重点聚焦于生成器对象的send方法. 一.send方法详解  我们知道生成器对象本质上是一个迭代器.但是它比迭代器对 ...

  6. Jquery遍历筛选数组的几种方法和遍历解析json对象|Map()方法详解

    Jquery遍历筛选数组的几种方法和遍历解析json对象|Map()方法详解 一.Jquery遍历筛选数组 1.jquery grep()筛选遍历数组 $().ready( function(){ v ...

  7. session的使用方法详解

    session的使用方法详解 Session是什么呢?简单来说就是服务器给客户端的一个编号.当一台WWW服务器运行时,可能有若干个用户浏览正在运正在这台服务器上的网站.当每个用户首次与这台WWW服务器 ...

  8. (转)Spring JdbcTemplate 方法详解

    Spring JdbcTemplate方法详解 文章来源:http://blog.csdn.net/dyllove98/article/details/7772463 JdbcTemplate主要提供 ...

  9. Java提高篇——equals()与hashCode()方法详解

    java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...

随机推荐

  1. 1-2、LVS之Linux集群系统基础

    Linux Cluster: 为了满足同一目的的需要,将多台主机组织起来解决统一问题的计算机的集合叫集群 Web Arch 虚拟化和云计算 自动化运维工具:ansible, puppet, zabbi ...

  2. Lintcode449-Char to Integer-Naive

    Description Convert a char to an integer. You can assume the char is in ASCII code (See Definition, ...

  3. SAP-批量修改主数据(客户、供应商、物料)

    SAP-批量修改主数据(客户.供应商.物料) TCODE: MASS 对于批量修改主数据如客户,供应商等,可以试用一下Mass , 它所能修改的范围如下: 选定要修改的对象后,点击运行,会要求选择需要 ...

  4. Tomcat日志系统详解

    综合:Tomcat下相关的日志文件 Cataline引擎的日志文件,文件名catalina.日期.log Tomcat下内部代码丢出的日志,文件名localhost.日期.log(jsp页面内部错误的 ...

  5. mysql5.7.23手动配置安装windows版

    1.mysql下载地址 官网:https://dev.mysql.com/downloads/mysql/5.7.html#downloads 官网我下载的是: 百度网盘:链接: https://pa ...

  6. Python 传递任意数量的实参

    在定义函数的时候如果你不知道该函数在使用的时候要接收多少的实参怎么办? 好在python提供了可以接收任意数量的实参的操作. # def sandwitch(*ingredents): # print ...

  7. 虹软2.0 免费人脸识别C#类库分享

    目前只封装了人脸检测部分的类库,供大家交流学习,肯定有问题,希望大家在阅读使用的时候及时反馈,谢谢!使用虹软技术开发完成 戳这里下载SDKgithub:https://github.com/dayAn ...

  8. nRF52832-GPIOTE部分

    GPIOTE部分学习思维导图 GPIOTE原理 1.1nRF52832寄存器类型 Task:任务寄存器,可以由程序或事件触发 Event:事件寄存器,事件可以产生中断和触发任务 Register:普通 ...

  9. AtCoder Regular Contest 103 E Tr/ee

    Tr/ee 思路:按照下图所示连接 代码: #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #inclu ...

  10. AtCoder Regular Contest 100 Equal Cut

    Equal Cut 思路: 枚举中间那个分界点,然后两边找使得切割后差值最小的点,这个可以用双指针 代码: #include<bits/stdc++.h> using namespace ...