JS的深浅拷贝的区别和实现

本文介绍了JavaScript中深拷贝和浅拷贝的概念,深入解析了它们的区别,并提供了三种实现深拷贝的方法,包括JSON.stringify和parse、递归调用以及jQuery的extend方法。同时,文章还讨论了valueOf()函数在不同数据类型中的行为,以及如何处理特殊类型的对象如Date和RegExp的深拷贝问题。
摘要由CSDN通过智能技术生成

前言:

栈堆、基本数据类型、引用数据类型 
栈堆:存放数据的地方 
基本数据类型:number,string,boolean,null,undefined. 
引用数据类型(Object类)有常规名值对的无序对象{a:1},数组[1,2,3],以及函数等。

浅拷贝概念:

如果是数组,我们可以利用数组的一些方法,比如slice,concat方法返回一个新数组的特性来实现拷贝,但假如数组嵌套了对象或者数组的话,使用concat方法克隆并不完整,如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或数组,就只会拷贝对象和数组的引用,这样我们无论在新旧数组进行了修改,两者都会发生变化,我们把这种复制引用的拷贝方式称为浅拷贝。

实现方式:

var shallowCopy function(obj){
   //只拷贝对象
   if(typeof obj !== 'object') return;
   //根据obj的类型判断是新建一个数组或对象
   var newObj = obj instanceof Array ? []:{};
   //遍历obj,并且判断是obj的属性才拷贝
    for(var key in obj){
      if(obj.hasOwnProperty(key)){
          newObj[key] = obj[key];
      }
   }
   return newObj;
}

深拷贝概念:

深拷贝是指完全拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,不会影响到另一个。

实现方式:

方法1:适用于对象和数组

JSON对象中的stringify可以把一个js对象序列化为一个JSON字符串,parse可以吧JSON字符串反序列化为一个js对象,通过这两种方法,可以实现对象的深复制,但是这个方法不能拷贝函数。

function deepClone(obj){
    let _obj = JSON.stringify(obj),
    objClone = JSON.parse(_obj);
    return objClone
}    
let a=[0,1,[2,3],4],
    b=deepClone(a);
a[0]=1;
a[2][0]=1;
console.log(a,b);

方法2:递归调用

var deepCopy = function(obj){
    if(typeof obj != 'object') return;
    var newObj = obj instanceof Array ? []:{};
    for(var key in obj){
       if(obj.hasOwnProperty(key)){
        newObj[key] = typeof obj[key] == 'object' ?deepCopy(obj[key]):obj[key];
    }
  }
   return newObj;
}

方法3:JQ的extend方法

$.extend( [deep ], target, object1 [, objectN ] )

deep表示是否深拷贝,为true为深拷贝,为false,则为浅拷贝

target Object类型 目标对象,其他对象的成员属性将被附加到该对象上。

object1  objectN可选。 Object类型 第一个以及第N个被合并的对象。 

let a=[0,1,[2,3],4],
    b=$.extend(true,[],a);
a[0]=1;
a[2][0]=1;
console.log(a,b);

通过递归可以实现对象的深度克隆,但是不论ES5或ES6实现,都有同样的缺陷,就是只能实现特定的object的深度复制(比如数组和函数),不能实现包装对象Number,String,Boolean,以及Date对象,RegExp对象的复制。

valueof()函数

所有的对象都有valueOf方法,valueOf方法对于:如果存在任意原始值,它就默认将对象转换为表示它的原始值。对象是复合值,而且大多数对象无法真正表示为一个原始值,因此默认的valueOf()方法简单地返回对象本身,而不是返回一个原始值。因此默认的valueOf()方法简单地返回对象本身,而不是返回一个原始值。数组、函数和正则表达式简单地继承了这个默认方法,调用这些类型的实例的valueOf()方法只是简单返回这个对象本身。

对于原始值或包装类(Number、String、Boolean):

function baseClone(base){
  return base.valueOf();
}

//Number 
var num = new Number(1);
var newNum = baseClone(num);

对于Date类型:

因为valueOf()方法,日期类定义的valueOf()方法会返回它的一个内部表示:1970年1月1日以来的毫秒数,因此我们可以在Date的原型上克隆定义的方法:

Date.prototype.clone = function(){
   return new Date(this.valueOf());
}

var date = new Date('2010');
var newDate = date.clone();
//newDate->   Fri Jan 2010 08:00:00 GMT+0800

对于正则对象RegExp:

RegExp.prototype.clone = function(){
   var pattern = this.valueOf();
   var flags ='';
   flags += pattern.global ?'g':'';
   flags += pattern.ignoreCase ? 'i':'';
   flags += pattern.multiline ?'m':'';
   return new RegExp(pattern.source,flags);
}


//var reg = new RegExp('/111/');
var newReg = reg.clone();

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值