前言

最近有人问我,如何将一个对象复制一份,因为他遇到了一个需求,需要将后端获取的数据,保存一份,原始数据会因为交互而发生变化,最终需要对比两份数据的异同。
他是一个刚入行的小朋友,他的实现方式就是新声明了一个变量,然后将数据赋值给了变量。本以为这就ok了,结果修改原数据,复制出来的变量中的内容,依然发生了变化。
在此,整理一下。(大中小)牛略过,仅为帮助新人,聊以解忧。

知识铺垫,值类型,与引用类型

我们用一个新的概念来理解这两种类型,连锁店和连锁店的钥匙。

1. 值类型包含如下:number,string,boolean,undefind,null;

变量的交换如同新开了一家连锁店,店面统一,但实际上新店与旧点之间,互无影响,各自运营,独立结算。 

var flagship  = 'xx连锁店'; //当前为旗舰店
var shop1 = flagship; //第一家连锁店
var shop2 = flagship; //第二家连锁店

2. 引用类型包含如下:对象,数组,函数

变量的交换等于现有一家店面的钥匙(变量地址引用)复制给了另外一个老板,此时两个人共同管理一家门店,两个人的行为都可能对着一间门店的运营造成影响。

var boss1 = {shop:'xx连锁店','state':'开业中'}
var boss2 = boss1;//复制了一把钥匙给boss2
boss2.state = '装修中'; //boss2将门店升级改造,暂时停业
console.log(boss1.state) // 装修中

由此可见,对应用类型的变量仅仅通过变量赋值,无法达到深拷贝的意图,仅仅只是浅拷贝。

如何去做呢

以下简单实现一个对纯数据对象(JSON)的深拷贝

1.实现值类型的复制:

从上面我们知道,值类型可以简单的通过变量赋值来实现深拷贝,所以先完成如下代码:

function clone(item) {
  var type = typeof item,
     baseTypes = ['boolean','number','string','undefined'],
     result;
  //使用typeof 可以准确判断出 boolean string number undefined
  //null 使用全等方式进行判断
  if(baseTypes.indexOf(type) >= 0 || item === null){
     result = item;
  }
  return result;
}

2.实现引用类型中数组的复制:

首先需要判断是否为数组,其次将数组进行遍历,分别复制数组中的内容,暂时不考虑数组中元素包含引用类型

function clone(item) {
  var result;
  //判断当前元素是否为数组,至于为什么这么判断,不深入了,有兴趣自己百度吧~
  if(Object.prototype.toString.call(item) === "[object Array]"){
    result = [];
    //循环数组,将数组内容放到新数组中(未考虑数组中元素是否包含引用类型)
    item.forEach(function (i) {
      result.push(i);
    })
  }
  return result;
}

3.实现引用类型中对象的复制:

首先需要判断是否为对象,其次将对象进行遍历,分别复制对象中的内容,暂时不考虑数组中元素包含引用类型

function clone1(item) {
  var result;
  //判断当前元素是否为对象,至于为什么这么判断,不深入了,有兴趣自己百度吧~
  if(Object.prototype.toString.call(item) === "[object Object]"){
    result = {};
    //遍历对象,将对象中内容放到新对象中(未考虑对象中元素是否包含引用类型)
    for(var i in item){
      result[i] = item[i];
    }
  }
  return result;
}

4.将对象或数组中包含引用类型值的情况考虑进去,一个简单的递归调用,整体代码如下

function clone(item) {
  var type = typeof item,
    baseTypes = ['boolean','number','string','undefined'],
    result;
  //使用typeof 可以准确判断出 boolean string number undefined
  //null 使用全等方式进行判断
  if(baseTypes.indexOf(type) >= 0 || item === null){
    result = item;
  }else if(Object.prototype.toString.call(item) === "[object Array]"){ // 判断是否为数组
    result = [];
    //循环数组,将数组内容放到新数组中
    item.forEach(function (i) {
      result.push(clone(i));
    })
  }else if(Object.prototype.toString.call(item) === "[object Object]"){ // 判断是否为对象
    result = {};
    //遍历对象,将对象中内容放到新对象中(未考虑对象中元素是否包含引用类型)
    for(var i in item){
      result[i] = clone(item[i]);
    }
  }else{
    result = item;
  }
    return result;
}

PS:还有没有其他简便方法呢

我们知道JSON,本身提供两个方法 JSON.stringify() 和 JSON.parse(),提供了将JSON对象转换为JSON结构的字符串,以及将JSON结构的字符串换换为JSON

so:简便方法来了

function clone(item) {
  var jsonStr = JSON.stringify(item);
  return JSON.parse(jsonStr);
}

如何深度复制一个javascript对象的更多相关文章

  1. 如何复制一个java对象(浅克隆与深度克隆)

    在项目中,有时候有一些比较重要的对象经常被当作参数传来传去,和C语言的值传递不同,java语言的传递都是引用传递,在任何一个地方修改了这个对象的值,就会导致这个对象在内存中的值被彻底改变.但是很多时候 ...

  2. Ajax 向后台提交一个 JavaScript 对象数组?

    var postArray= new Array(); var temp = new Object(); temp.id='1'; temp.name='test'; postArray.push(t ...

  3. 第六章:Javascript对象

    对象是javascript的基本数据类型.对象是一种复合值.它将很多值(原始值 或者其他对象)聚合在一起.可通过名字访问这些值.对象也可以看做是属性的无序集合,每个属性都有一个名/值.属性名是字符串, ...

  4. JavaScript对象进阶

    要了解JavaScript对象,我们可以从对象创建.属性操作.对象方法这几个方面入手.概括起来,包括以下几模块: 1.创建对象 1.1 对象直接量 对象直接量是创建对象最简单的方式,由若干名/值对组成 ...

  5. 【Stack Overflow -- 原创加工、原创整理、生产实战】-- 深度复制

    一.说明 1.本程序的核心代码不是我原创的,是我在Stack Overflow上搜集后加工出来的,原作者已忘记了~ 2.这段程序是我在上海携程(2014年左右)上班时整理并在生产环境应用的,先后经历了 ...

  6. 如何理解javaScript对象?

    在我们生活中,常常会提到对象一词,如:你找到对象了吗?你的对象是谁呀?等等. 在我们家庭中,有男友的女青年都会说我有对象了,那么她的对象是XX(她的男友). 夫妻间呢?都会说我的爱人是谁谁谁,现在我们 ...

  7. 深入理解javascript对象系列第二篇——属性操作

    × 目录 [1]查询 [2]设置 [3]删除[4]继承 前面的话 对于对象来说,属性操作是绕不开的话题.类似于“增删改查”的基本操作,属性操作分为属性查询.属性设置.属性删除,还包括属性继承.本文是对 ...

  8. 如何判断Javascript对象是否存在

    Javascript语言的设计不够严谨,很多地方一不小心就会出错. 举例来说,请考虑以下情况. 现在,我们要判断一个全局对象myObj是否存在,如果不存在,就对它进行声明.用自然语言描述的算法如下: ...

  9. JavaScript基础——使用JavaScript对象

    JavaScript有许多内置对象,如Number(数字).Array(数组).String(字符串).Date(日期)和Math(数学).这些内置对象都有成员属性和方法.除了JavaScript对象 ...

随机推荐

  1. PS 图像调整算法——阈值

    PS里面这个算法,先将图像转成灰度图像,然后根据给定的阈值,大于该阈值的像素赋值为1,小于该阈值的赋值为0. if x>T, x=1; if x<T, x=0; 原图: 效果图:阈值为 1 ...

  2. Android特效专辑(三)——自定义不一样的Toast

    Android特效专辑(三)--自定义不一样的Toast 大家都知道,Android的控件有时候很难满足我们的需求,所以我们需要自定义View.自定义的方式很多,有继承原生控件也有直接自定义View的 ...

  3. ZYThumbnailTableView类似于小型阅读器

    Demo github地址: https://github.com/liuzhiyi1992/ZYThumbnailTableView  原文地址:http://zyden.vicp.cc/zythu ...

  4. javascript加RoR实现JSONP

    我们知道不同域中的js代码受同源策略的限制,不同域中的AJAX同样受此限制,不过使用html中的script远程脚本可以跳过该限制,下面我们实际看一下利用RoR和js如何实现所谓的JSONP. 这里只 ...

  5. ruby读取源代码自身的一种方法

    我们知道ruby中如果源代码中一行开头(必须在行的开头)有__END__标示,则表示下面的都是数据行,可以用IO对象DATA来访问这些行.但是如果我们用DATA.rewind一下的话,就可以将文件流指 ...

  6. C# 合并多种格式文件为PDF

    文档合并是一种高效文档处理方式.如果能够有一个方法能将多种不同类型的文档合并成一种文档格式,那么在文档存储管理上将为我们提供极大的便利.因此,本篇文章介绍了一种如何使用免费组件Free Spire.O ...

  7. MySQL 8 新特性之Invisible Indexes

    背景 索引是把双刃剑,在提升查询速度的同时会减慢DML的操作.毕竟,索引的维护需要一定的成本.所以,对于索引,要加上该加的,删除无用的.前者是加法,后者是减法.但在实际工作中,大家似乎更热衷于前者,而 ...

  8. centos6-7克隆主机网卡无法启动问题

    1,centos6和redhat6左右的版本  第一,先找到网卡的mac地址,将其配置在配置文件中,重新启动网卡. 故障产生的原因: 由于克隆虚拟机,vmware只是修改了虚拟机的名字等信息,并没有修 ...

  9. json.parseArray源码解析

    json.parseArray源码解析 public static <T> List<T> parseArray(String text, Class<T> cla ...

  10. javaWeb安全漏洞修复总结

    1 Web安全介绍1 2 SQL注入.盲注1 2.1 SQL注入.盲注概述 1 2.2 安全风险及原因 2 2.3 AppScan扫描建议 2 2.4 应用程序解决方案 4 3 会话标识未更新7 3. ...