深拷贝和浅拷贝

一、 基本数据类型的拷贝(复制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

// }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349