Object对象的浅拷贝与深拷贝方法详解
- /* ===================== 直接看代码 ===================== */
- <!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对象的浅拷贝与深拷贝方法详解的更多相关文章
- 并发编程(六)Object类中线程相关的方法详解
一.notify() 作用:唤醒一个正在等待该线程的锁的线程 PS : 唤醒的线程不会立即执行,它会与其他线程一起,争夺资源 /** * Object类的notify()和notifyAll()方法详 ...
- 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 ...
- 深拷贝与浅拷贝(mutableCopy与Copy)详解 iOS
深拷贝与浅拷贝(mutableCopy与Copy)详解 iOS ios中并不是所有的对象都支持copy,mutableCopy,遵守NSCopying 协议的类可以发送copy消息,遵守NSMutab ...
- 用Newtonsoft将json串转为对象的方法(详解)
首先,将json串转为一个JObject对象: JObject jo = (JObject)JsonConvert.DeserializeObject(CurrentSelectedItemReq) ...
- Python学习之旅—生成器对象的send方法详解
前言 在上一篇博客中,笔者带大家一起探讨了生成器与迭代器的本质原理和使用,本次博客将重点聚焦于生成器对象的send方法. 一.send方法详解 我们知道生成器对象本质上是一个迭代器.但是它比迭代器对 ...
- Jquery遍历筛选数组的几种方法和遍历解析json对象|Map()方法详解
Jquery遍历筛选数组的几种方法和遍历解析json对象|Map()方法详解 一.Jquery遍历筛选数组 1.jquery grep()筛选遍历数组 $().ready( function(){ v ...
- session的使用方法详解
session的使用方法详解 Session是什么呢?简单来说就是服务器给客户端的一个编号.当一台WWW服务器运行时,可能有若干个用户浏览正在运正在这台服务器上的网站.当每个用户首次与这台WWW服务器 ...
- (转)Spring JdbcTemplate 方法详解
Spring JdbcTemplate方法详解 文章来源:http://blog.csdn.net/dyllove98/article/details/7772463 JdbcTemplate主要提供 ...
- Java提高篇——equals()与hashCode()方法详解
java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...
随机推荐
- 2、Python程序控制结构(0530)
条件测试: 1.if 条件测试表达式 python的比较操作 1.所有的python对象都支持比较操作 可用于测试相等性.相对大小等: 如果是符合对象,python会检查其所有部分,包括自动遍历各级嵌 ...
- Java单例设计模式(实现Java的一个类只有一个对象)
单例设计模式的定义:单例设计模式是一种软件设计模式,在它的核心包含一个称为单例类的核心类. 核心便是希望一个类只有一个对象. 如何实现类在内存中只有一个对象呢? 第一步:构造私有:第二步:本身提供一 ...
- Ubuntu18.04下安装MySQL
Ubuntu上安装MySQL非常简单只需要几条命令就可以完成. 1. sudo apt-get install mysql-server 2. apt-get isntall mysql-client ...
- config配置
<?php /** * User: Eden * Date: 2019/3/30 * 共有内容 */ /** CREATE TABLE `tf_configs` ( `id` int(11) N ...
- 总要先爬出坑的JEE架构
先来看看官网对它的定义. Java平台企业版(Java EE)是社区驱动的企业软件的标准.Java EE是使用Java Community Process开发的,其中包括来自行业专家,商业和开源组织, ...
- 从classloader的变更说起
classloader从1.6到1.7整体分成了两个版本.重点区别就是并行类加载. 1.6版本 protected synchronized Class loadClass(String name, ...
- wow 滚动动画
1.demo <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset=" ...
- Android application backup
警告 AndroidMenifest中application标签下android:allowBackup="true"时,会警告: Warning:On SDK version 2 ...
- MySQL学习(五)
查询数据的学习与练习 建立一个表 CREATE TABLE goods ( `goos_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, `cat_ ...
- H5多媒体(用面向对象的方法控制视频、音频播放、暂停、延时暂停)
视频,音频播放器会是我们在工作中用到的一些h5新标签,它自带一些属性,比如暂停播放,快进快退,但是,我们经常不用原生的样式或者方法,我们需要自定义这些按钮来达到我们需要的样式,也需要我们自定义来实现一 ...