js 深浅拷贝的整理

好记性不如烂笔头。记在脑子里不如做点笔记。

什么是深浅拷贝?

在理解这个问题之前,我们要先去了解一下js的数据类型,js数据类型分为基本数据类型引用数据类型

基本数据类型:
		string,number,null,undefined,boolean
引用数据类型:
		object对象(array,function,date,reg)

我们知道了js的数据类型,现在就可以来了解什么是深浅拷贝,先看基本数据类型的拷贝,代码如下:

var a = 2;  // 定义a变量赋值为2
var b = a;  // 把a变量赋值给b
a = 1;     // 修改a的值
console.log(a, b); // 1, 2 

由上可以看出,a的值改变之后,b的值并没有跟着改变,再来看看引用类型的拷贝,代码如下:

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

结果:在这里插入图片描述
操作和基本数据类型一样,b会跟着a改变,为什么会出现这样的情况呢?因为基本数据类型保存在栈内存里,而引用数据类型保存在堆内存里,保存在栈内存的必须是大小固定的数据,引用类型的大小不固定,只能保存在堆内存中,而我们定义的变量实际保存的是一个指针,这个指针指向的是堆内存。
在这里插入图片描述
代码解析:
1.基本数据类型拷贝:
当var a = 2的时候在栈内存中新开辟了一个空间保存a变量值为2,进行var b = a的时候是在内存中又开辟了新的空间保存着b,所以a和b两个变量互不相关。
2.引用数据类型拷贝:
进行var a = [1,2,3,4]的时候,在栈内存中保存的只是一个指针也可以说是地址,这个指针指向的是堆内存的一个对象,堆内存中保存着这个对象,当var b = a的时候,我们进行了复制但是复制的只是栈内存中的指针,堆内存中的本身对象并没有被复制,所以a[1] = 0的时候,b也改变了,因为a和b指向的是同一个对象。这就是浅拷贝。

由上总结得出:基本数据类型的拷贝就是直接赋值的操作,而深浅拷贝相对应的就是引用数据类型。

浅拷贝

浅拷贝只是拷贝基本类型的数据,如果所拷贝的对象的属性等于数组或另一个对象那就是只拷贝了指针,而没有拷贝堆内存中存储内容的对象,只要这个对象所改变了,所有指向这个对象的变量的值都会改变。看代码:戳这里

var Nation = {  
     nation: '中国'
};
function extendCopy(p) {  
	var c = {};  
    for (var i in p) {    
         c[i] = p[i];  
    }  
    return c;
}
var Doctor = extendCopy(Nation);
Doctor.career = '医生';
Doctor.nation = '美国';
console.log(Doctor.nation); // 美国
console.log(Nation.nation); // 中国
console.log(Doctor.career); // 医生

好像看起来都没错,Doctor对象新增了career 属性,而Nation对象并没有career 属性,他们好像没有什么关联,如果我们给属性的值是一个对象呢?再来看看:

 // 封装一个浅拷贝函数:
  function simpleClone(initalObj) {    
     var obj = {};    
     for ( var i in initalObj) {
            obj[i] = initalObj[i];
     }    
     return obj;
 }
 // 定义一个多层次的对象
  var obj = {
          a: "hello",
          b:{
              a: "world",
              b: 21
          },
          c:["Bob", "Tom", "Jenny"],
          d:function() {
              alert("hello world");
          }
   }
   // 赋值obj对象
   var obj1 = simpleClone(obj);
   obj1.c = ['mm', "Tom", "Jenny"];   // 改变obj1中的c属性的值
   // 打印一下
   console.log('obj=>>>',obj);  //obj.c =>  ["Bob", "Tom", "Jenny"]
   console.log('obj1=>>>',obj1);  //obj.c => ["mm", "Tom", "Jenny"]
   // 再来改变数组中的第一个元素  把上面的赋值和打印注释一下
   obj1.c[0] = 'bb'; // 浅拷贝时,改变属性的属性值,改变原对象
   // 再打印一下
   console.log('obj=>>>',obj); //obj.c => ["bb", "Tom", "Jenny"]
   console.log('obj1=>>>',obj1);  //obj.c => ["bb", "Tom", "Jenny"]

哦豁 完蛋, obj1.c[0] = 'bb’执行这一步的时候两个对象都改变了,为啥执行obj1.c = [‘mm’, “Tom”, “Jenny”]的时候两个对象没有关联,因为浅拷贝是只拷贝一层,把 obj1.c作为一个整体改变了,而obj1.c[0] = 'bb’深层次的对象的改变就需要用到深拷贝了。
另外:Object.assign()也能实现浅拷贝

深拷贝

深拷贝的实现方式有很多种

  1. 最简单的json方法
    JSON.parse(JSON.stringify(obj))
  2. 使用Object.create()方法
function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    var prop = initalObj[i];        // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
    if(prop === obj) {            
      continue;
    }        
    if (typeof prop === 'object') {
      obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
    } else {
      obj[i] = prop;
    }
  }    
  return obj;
}
  1. 递归
function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    var prop = initalObj[i];        // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
    if(prop === obj) {            
      continue;
    }        
    if (typeof prop === 'object') {
      obj[i] = (prop.constructor === Array) ? [] : {};            
      arguments.callee(prop, obj[i]);
    } else {
      obj[i] = prop;
    }
  }    
  return obj;
}
var str = {};
var obj = { a: {a: "hello", b: 21} };
deepClone(obj, str);
console.log(str.a);

代码摘自:https://blog.youkuaiyun.com/weixin_37719279/article/details/81240658

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值