zoukankan      html  css  js  c++  java
  • 如何深度复制一个javascript对象

    前言

    最近有人问我,如何将一个对象复制一份,因为他遇到了一个需求,需要将后端获取的数据,保存一份,原始数据会因为交互而发生变化,最终需要对比两份数据的异同。
    他是一个刚入行的小朋友,他的实现方式就是新声明了一个变量,然后将数据赋值给了变量。本以为这就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);
    }
  • 相关阅读:
    基于keepalived双主模型的高可用LVS
    ViewFlipper实现ViewPager的页面切换效果
    C++,Python,Go对照学习-01
    matlab figure 调整大小、字体、线宽
    学术研究 —— 常用结论、说法
    学术研究 —— 常用结论、说法
    OpenGL(十六) 鼠标、键盘交互响应事件
    N+1:创新点的设计
    N+1:创新点的设计
    数学中的物理、几何概念与含义
  • 原文地址:https://www.cnblogs.com/chenqf/p/7891048.html
Copyright © 2011-2022 走看看