深拷贝和浅拷贝

一、 基本数据类型的拷贝(复制copy)深拷贝和浅拷贝 

深拷贝和浅拷贝是针对复杂数据类型来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝

基本数据类型  值传递    

a = 1.1;b = a;b = 2; console.log(a,b)                   Number

a = 'hello';b = a;b = 3; console.log(a,b)                 String

a = false;b = a;b = 'sss'; console.log(a,b)              Boolean  

a = undefined;b = a;b = false; console.log(a,b)     Undefined    

 a = null;b = a;b = undefined; console.log(a,b)        Null

深拷贝

  深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。 深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。

 浅拷贝

 浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。

可以看出浅拷贝只最第一层属性进行了拷贝,当第一层的属性值是基本数据类型时,新的对象和原对象互不影响,但是如果第一层的属性值是复杂数据类型,那么新对象和原对象的属性值其指向的是同一块内存地址。

二、复杂数据类型(object)的拷贝  地址传递

常用的复杂数据类型包括:{ }、[ ]、function(){} 、Date(时间) 、RegExp 、null(这个比较特殊)等

 1、我们依然用一的简单赋值(=)来进行一遍操作(赋值)

   经过实践我们会发现:

     1、当类型为{}、[]的时候,改变b的值,a也会跟着一起变化。

     2、当类型为Date、function、RegExp的时候,a保持不变。

   总结:我们发现{}或者[]时,简单的赋值操作并不能实现它们的拷贝,只是改了b的指向,使a和b都指向同一个引用,随意改变一个,都会影响另外一个的值。 

    // {}

    // a = {name: 'abc'};b = a;b.name = 'sss';

    // console.log(a,b)

    // // []

    // a = ['a','b','c'];b = a;b[1] = 'd';

    // console.log(a,b)

    // // function

    // a = function(){ alert('aaa'); };b = a;b = function(){ alert('bbb'); };

    // console.log(a.toString(),b.toString())

    // // Date

    // a = new Date('2018-10-11 00:00:00');b = a;b = new Date('1970-01-01 00:00:00');

    // console.log(a,b)

    // // RegExp

    // a = new RegExp('abc');b = a;b = new RegExp('aaa');

    // console.log(a,b)

    // 2、Object.assign 和 for in进行{}和[]的拷贝(浅拷贝--只能拷贝一层)

    // Object.assign

    // a = {name: 'aaa'};b = Object.assign({}, a);

    // b.name = 'bbb'; 

    // console.log(a,b)

    // a = [1,2,3];b = Object.assign([], a);b[1] = 4; 

    // console.log(a,b)

    // // for in

    // var copy = function(a) {

    //  var res = a.constructor();

    //  console.log(res)

    //  for(var key in a) {

    //  if(a.hasOwnProperty(key)) {

    //    res[key] = a[key];

    //  }

    //  }

    //  return res;

    // }

    // a = {name: 'aaa'};b = copy(a);b.name = 'bbb'; 

    // console.log(a,b)

    // a = [1,2,3];b = copy(a);b[1] = 4; 

    // console.log(a,b)

  // a = {name:'aaa',people:{name: 'abc'}};b = Object.assign({}, a);b.people.name = 'def';

  // console.log(a,b)                       

  // // for in

  //  var copy = function(a) {

  //    var res = a.constructor();

  //    for(var key in a) {

  //    if(a.hasOwnProperty(key)) {

  //      res[key] = a[key];

  //    }

  //    }

  //    return res;

  //  }

  // a = {name:'aaa',people:{name: 'abc'}};b = copy(a);b.people.name = 'def';

  // console.log(a,b)

  // a = [1,2, {name: 'aaa'}];b = Object.assign([], a);b[2].name = 'bbb';

  // console.log(a,b)

  // a = [1,2, {name: 'aaa'}];b = copy(a);b[2].name = 'bbb';

  // console.log(a,b)

       深拷贝和浅拷贝是针对复杂数据类型来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝。

  深拷贝

      深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。 深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。

   浅拷贝

       浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。 可以使用 for in、 Object.assign、 扩展运算符 ... 、Array.prototype.slice()、Array.prototype.concat() 等

// var array = [

    //    { number: 1 },

    //    { number: 2 },

    //    { number: 3 }

    // ];

    // var copyArray = array.slice();

    // copyArray[0].number = 100;

    // console.log(array);

    // console.log(copyArray);

    // let obj = {

    //    name: 'Yvette',

    //    age: 18,

    //    hobbies: ['reading', 'photography']

    // }

    // let obj2 = Object.assign({}, obj);

    // let obj3 = {...obj};

    // obj.name = 'Jack';

    // obj.hobbies.push('coding');

    // console.log(obj);

    // console.log(obj2);

    // console.log(obj3);

       可以看出浅拷贝只最第一层属性进行了拷贝,当第一层的属性值是基本数据类型时,新的对象和原对象互不影响,但是如果第一层的属性值是复杂数据类型,那么新对象和原对象的属性值其指向的是同一块内存地址。

     1.深拷贝最简单的实现是: JSON.parse(JSON.stringify(obj))

    JSON.parse(JSON.stringify(obj)) 是最简单的实现方式,但是有一些缺陷:

     //对象的属性值是函数时,无法拷贝。

    //  原型链上的属性无法拷贝

    //  不能正确的处理 Date 类型的数据

    //  不能处理 RegExp

    //  会忽略 symbol

    //  会忽略 undefined

递归函数

如果一个函数在内部调用自身,这个函数就叫做递归函数

递归函数:

      实现一个 deepClone 函数 (深拷贝,完美)

      // 如果是基本数据类型,直接返回

      // 如果是 RegExp 或者 Date 类型,返回对应类型

      // 如果是复杂数据类型,递归。

      // 考虑循环引用的问题

    // var show={

    //    btn:"btn",

    //    init:function(){

    //        var that=this;

    //        alert(this);

    //        this.btn.click(function(){

    //                that.change();

    //                alert(this);

    //        })           

    //    },

    //    change:function(){

    //        this.btn.css({'background':'green'});

    //        person={

    //          name:"king",

    //          show:function(){

    //            console.log(this.name)

    //          }

    //        }

    //    }

    // }



    // function deepClone(obj, hash = new WeakMap()) { //递归拷贝

    //    if (obj instanceof RegExp) return new RegExp(obj);

    //    if (obj instanceof Date) return new Date(obj);

    //    if (obj === null || typeof obj !== 'object') {

    //        //如果不是复杂数据类型,直接返回

    //        return obj;

    //    }

    //    if (hash.has(obj)) {

    //        return hash.get(obj);

    //    }

        /**

        * 如果obj是数组,那么 obj.constructor 是 [Function: Array]

        * 如果obj是对象,那么 obj.constructor 是 [Function: Object]

        */

    //    let t = new obj.constructor();

    //    hash.set(obj, t);

    //    for (let key in obj) {

    //        //递归

    //        if (obj.hasOwnProperty(key)) {//是否是自身的属性

    //            t[key] = deepClone(obj[key], hash);

    //        }

    //    }

    //    return t;

    // }


    // var show2 = cloneObject(show)

    // console.log(show2)

//递归函数

// function cloneObject (obj) {

  // var newObj = {}  //如果不是引用类型,直接返回

  // if (typeof (obj) !== 'object') {

  //   return obj

  // }

  // //如果是引用类型,遍历属性

  // else{

  // for (var attr in obj) {

  // //如果某个属性还是引用类型,递归调用

  //   newObj[attr] = cloneObject(obj[attr])

  // }

  // }

  // return newObj

// }

你可能感兴趣的:(深拷贝和浅拷贝)