1.什么是拷贝,什么是深拷贝与浅拷贝?

(1)拷贝:拷贝就是为了复用原对象的部分或全部数据,在原对象的基础上通过复制的方式创建一个新的对象。

(2)浅拷贝:浅拷贝是对象的逐位复制。创建一个新对象,该对象具有原始对象中值的精确副本。如果对象的任何字段是对其他对象的引用,则只复制引用地址,即,复制内存地址。(默认情况下引用类型(object)都是浅拷贝)

         通俗易懂的说,浅拷贝复制的是对象的引用地址,没有开辟新的栈,复制的结果是两个对象指向同一个地址,所以修改其中一个对象的属性,另一个对象的属性也跟着改变了。

 

 (3)深拷贝复制所有字段,并复制字段所指向的动态分配内存。深拷贝发生在对象及其引用的对象被复制时。(默认情况下基本数据类型(number,string,null,undefined,boolean)都是深拷贝。)

          通俗易懂的说,深拷贝会开辟新的栈,两个对象对应两个不同的地址,修改对象A的属性,并不会影响到对象B。

 

 2.深拷贝与浅拷贝的区别

(1)直接区别:浅拷贝就是双方不是独立的,还会互相影响;深拷贝是不会影响到彼此,是独立的个体;

(2)内在区别:浅拷贝就是简单的把指向别人的值的一个指针给复制过来,深拷贝就是实实在在的把别人的值给复制过来。

     当拷贝的是js基本数据类型时,都会是深拷贝;如果拷贝的是js引用数据类型时,简单的赋值过来的时候就是浅拷贝,需要做一些特殊处理让它变成深拷贝。

 3.理解深拷贝和浅拷贝

 js的数据类型:

  • js的六大数据类型:Number, String, Boolean, Undefined , Null , Object;
  • 基本数据类型:Number,String,Boolean,Undefined, Null;
  • 引用数据类型:Object , Array, Function
//拷贝基本数据类型
var a = 6;
var b = a;
a = 9;
console.log(a,b);//9 6
//当拷贝的是引用数据类型时
var a = [3,6,9];
var b = a;
a[0] = 6;
console.log(a,b);//[6,6,9] [6,6,9]

4.浅拷贝和深拷贝的方法

 (1)浅拷贝

  • Object.assign() 

    Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。

注:Object.assign()拷贝的是(可枚举)属性值。假如源值是一个对象的引用,它仅仅会复制其引用值。

       如果对象的属性值为简单类型(如Number,String),通过Object.assign({},Obj)得到的新对象为深拷贝;如果属性值为对象或其它引用类型,那对于这个对象而言其实是浅拷贝的。

	let a = {
	    name:"datiechui",
	    like:{
	       food:"chicken",
	       color:"blue"
	    }
	}
	let b = Object.assign({},a);
	console.log(a,b)

          改变a,观察b的变化:

let a = {
	    name:"datiechui",
	    like:{
	       food:"chicken",
	       color:"blue"
	    }
	}
	let b = Object.assign({},a);
	a.name = "xiaobuding";
	a.like.color = "green";
	console.log(a,b)

        b中属于基本数据类型的name属性的值没有发生改变,但是属于引用数据类型的like里面的数值发生了和a一样的变化,因为指向了同一个地址。

  •  slice() 
  • concat() 
let a = [1,2,[3,4]];
let b = a.slice(0);
console.log(a,b);//[1,2,[3,4]]  [1,2,[3,4]]

a[0] = 2;
a[2][0] = 4;
console.log(a,b)//[2,2,[4,4]]  [1,2,[4,4]]

(2)深拷贝

递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝

//定义检测数据类型的功能函数
    function checkedType(target) {
      return Object.prototype.toString.call(target).slice(8, -1)
    }
    //实现深度克隆---对象/数组
    function clone(target) {
      //判断拷贝的数据类型
      //初始化变量result 成为最终克隆的数据
      let result, targetType = checkedType(target)
      if (targetType === 'Object') {
        result = {}
      } else if (targetType === 'Array') {
        result = []
      } else {
        return target
      }
      //遍历目标数据
      for (let i in target) {
        //获取遍历数据结构的每一项值。
        let value = target[i]
        //判断目标结构里的每一值是否存在对象/数组
        if (checkedType(value) === 'Object' ||
          checkedType(value) === 'Array') { //对象/数组里嵌套了对象/数组
          //继续遍历获取到value值
          result[i] = clone(value)
        } else { //获取到value值是基本的数据类型或者是函数。
          result[i] = value;
        }
      }
      return result
    }
  • JSON.stringify()

         将需要深拷贝的对象序列化为一个 JSON 字符串,然后根据这个字符串解析出一个结构和值完全一样的新对象;

let a = {
	    name:"datiechui",
	    like:{
	       food:"chicken",
	       color:"blue"
	    }
	}
let b = JSON.parse(JSON.stringify(a));
console.log(a,b);
let a = {
	    name:"datiechui",
	    like:{
	       food:"chicken",
	       color:"blue"
	    }
	}
let b = JSON.parse(JSON.stringify(a));
a.name = "xiaobuding";
a.like.color = "green";
console.log(a,b);

       由此看出,改变a,b不改变。

注:该方法需要保证对象是安全的,比如属性值不能是 undefined、symbol、函数、日期和正则。

  • $.extend() 

         $.extend() 方法属于 jquery 的方法。此方法实现深拷贝的基本思路是:如果是基本值或除了对象或数组之外的引用值,直接赋值;如果是对象或数组就需要进行递归,直到递归到基本值或除了对象或数组之外的引用值为止。

5.总结

(1)拷贝是为了部分或全部复用原对象的属性,在元对象的基础上创建一个新的对象。

(2)浅拷贝是拷贝后两个对象地址不相等,但两个对象的部分属性地址相等,新对象并没有拷贝所有的属性,而是复用原对象中的值。

(3)深拷贝是拷贝后两个对象不仅地址不相等,两个对象的所有属性地址都不相等。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐