资讯专栏INFORMATION COLUMN

如何深度克隆一个对象

TIGERB / 1999人阅读

摘要:如何深度克隆一个对象在我们日常工作中经常会遇到需要去克隆一个对象比如多个地方用到的公共的图表基本参数的配置相信很多人会想到用和方法去克隆一个对象,这个可以明确告诉大家这些都是些不靠谱的浅度克隆。

如何深度克隆一个对象
在我们日常工作中经常会遇到需要去克隆一个对象比如多个地方用到的公共的图表基本参数的配置

相信很多人会想到用 Object.assign, JSON.stringifyJSON.parse 方法去克隆一个对象,这个可以明确告诉大家这些都是些不靠谱的浅度克隆。

我们先来试一下 Object.assign 在控制台执行下列操作

大家有没有发现联动了。关于此方法具体请参考文档
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

接下来我们看下 JSON.stringifyJSON.parse 克隆对象,同样在控制输入

大家有没有发现什么异常?虽然 JSON.stringify(value[, replacer[, space]]) 可以处理但是太麻烦了,这个方法我就不多说了具体还是参考文档
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

下面咋们来看一种稍微靠谱的一种方式。在本站搜的前几条中发现的。
function isArray (arr) {
    return Object.prototype.toString.call(arr) === "[object Array]";  
}
// 深度克隆
function deepClone (obj) {  
    if(typeof obj !== "object" && typeof obj !== "function") {
        return obj;        //原始类型直接返回
    }
    var o = isArray(obj) ? [] : {}; 
    for(i in obj) {  
        if(obj.hasOwnProperty(i)){ 
            o[i] = typeof obj[i] === "object" ? deepClone(obj[i]) : obj[i]; 
        } 
    } 
    return o;
}

看是靠谱是真是假我们来验证一把 还是在控制台输入

大家发现什么异常的了吗?

这个没有区分具体的对象,在此问下大家js的对象有哪些呢?相信一般人答不出来4个
[object Object], [object Array], [object Null], [object RegExp], [object Date], [object HTMLXXElement], [object Map],[object Set],... 等等一系列

检测类型使用 Object.prototype.toString.call(xxx)typeof

我们分析下上面对象中哪些是引用类型需要特殊处理呢?相信大家都不陌生了。[object Object][object Array]

好!详细大家思路有了,咋们用递归来实现一把吧!

const deepClone = function(obj) {
  // 先检测是不是数组和Object
  // let isMap = Object.prototype.toString.call(obj) === "[object Map];
  // let isSet = Object.prototype.toString.call(obj) === "[object Set];
  // let isArr = Object.prototype.toString.call(obj) === "[object Array]";
  let isArr = Array.isArray(obj);
  let isJson = Object.prototype.toString.call(obj) === "[object Object]";
  if (isArr) {
    // 克隆数组
    let newObj = [];
    for (let i = 0; i < obj.length; i++) {
      newObj[i] = deepClone(obj[i]);
    }
    return newObj;
  } else if (isJson) {
    // 克隆Object
    let newObj = {};
    for (let i in obj) {
      newObj[i] = deepClone(obj[i]);
    }
    return newObj;
  }
  // 不是引用类型直接返回
  return obj;
};

Object.prototype.deepClone = function() {
  return deepClone(this);
};
咋们先不考虑Map Set Arguments [object XXArrayBuffer] 对象了原理都是一样

各种情况分析完了才说算是真克隆
我们在控制台看下

注意先要把方法在控制台输进去,在调试

是不是解决了? 在此并没有结束。 专注的伙伴们相信发现了对象中包含了个 deepClone 方法,具体细节我们在此就不多说了,我们给 Object 添加了个 Object.prototype.deepClone方法导致了每个对象都有了此方法。

原则上我们不允许在原型链上添加方法的,因为在循环中 for in, Object.entries, Object.values, Object.keys 等方法会出现自定义的方法。

相信熟悉 Object 文档的伙伴人已经知道解决方案了,

Object.defineProperty 这个方法给大家带来了福音 具体参考 Object 文档。我们使用一个enumerable (不可枚举)属性就可以解决了。

在原来基础上添加以下代码即可。

Object.defineProperty(Object.prototype, "deepClone", {enumerable: false});

在看控制台

同样上面方法中也是无法克隆一个不可枚举的属性。

完整代码如下

const deepClone = function(obj) {
  // 先检测是不是数组和Object
  // let isArr = Object.prototype.toString.call(obj) === "[object Array]";
  let isArr = Array.isArray(obj);
  let isJson = Object.prototype.toString.call(obj) === "[object Object]";
  if (isArr) {
    // 克隆数组
    let newObj = [];
    for (let i = 0; i < obj.length; i++) {
      newObj[i] = deepClone(obj[i]);
    }
    return newObj;
  } else if (isJson) {
    // 克隆Object
    let newObj = {};
    for (let i in obj) {
      newObj[i] = deepClone(obj[i]);
    }
    return newObj;
  }
  // 不是引用类型直接返回
  return obj;
};

Object.prototype.deepClone = function() {
  return deepClone(this);
};
Object.defineProperty(Object.prototype, "deepClone", {enumerable: false});
为了兼容低版本浏览器需要借助 babel-polyfill;

好了,深度克隆介绍到此。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/94181.html

相关文章

  • 【转】JavaScript 对象深度克隆

    摘要:在聊以下简称深度克隆之前,我们先来了解一下中对象的组成。克隆或者拷贝分为种浅度克隆深度克隆。浅度克隆基本类型为值传递,对象仍为引用传递。 该文转载自http://www.cnblogs.com/zichi/p/4568150.html,有部分修改。 在聊JavaScript(以下简称js)深度克隆之前,我们先来了解一下js中对象的组成。在 js 中一切实例皆是对象,具体分为 原始类型 ...

    JowayYoung 评论0 收藏0
  • 一起学设计模式 - 原型模式

    摘要:原型模式是创建模式的一种,其作用是提高创建效率,减少计算机资源开销,与工厂模式类似的是,都屏蔽了对象实例化的过程概述原型模式是模式的一种,其特点就是通过克隆拷贝的方式来,节约创建成本和资源,被拷贝的对象模型就称之为原型。 原型模式(Prototype Pattern)是创建模式的一种,其作用是提高创建效率,减少计算机资源开销,与工厂模式类似的是,都屏蔽了对象实例化的过程... 概述 ...

    DevTalking 评论0 收藏0
  • js对象详解(JavaScript对象深度剖析,深度理解js对象)

    摘要:对象详解对象深度剖析,深度理解对象这算是酝酿很久的一篇文章了。用空构造函数设置类名每个对象都共享相同属性每个对象共享一个方法版本,省内存。 js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了。 JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕。 平时发的文章基本都是开发中遇到的问题和对...

    CatalpaFlat 评论0 收藏0
  • 浅析深度克隆(deepclone)

    摘要:深度克隆方法,返回一个新的克隆对象这里得说明深拷贝与钱拷贝的区别,浅拷贝是复制一个对象的引用,深拷贝是一个新的对象,与原对象有着不同的内存地址方法一通过递归遍历一个对象,返回一个新的对象深拷贝要深拷贝的值判断某个对象是否含有指定的属性该方法 深度克隆方法,返回一个新的克隆对象这里得说明深拷贝与钱拷贝的区别,浅拷贝是复制一个对象的引用,深拷贝是chone一个新的对象,与原对象有着不同的内...

    yhaolpz 评论0 收藏0
  • Vue的computed和watch的细节全面分析

    摘要:定义是一个计算属性类似于过滤器对绑定到的数据进行处理用法不可在里面定义如果定义会报如下图片的错误因为对应的作为计算属性定义并返回对应的结果给这个变量变量不可被重复定义和赋值和用法回调函数当需要读取当前属性值是执行,根据相关数据计算并返回当前 1.computed 1.1 定义 是一个计算属性,类似于过滤器,对绑定到view的数据进行处理 1.2 get用法 data: { ...

    lastSeries 评论0 收藏0

发表评论

0条评论

TIGERB

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<