关于深拷贝与浅拷贝

本文介绍了JS中赋值、浅拷贝与深拷贝的区别。先阐述了堆和栈的概念,以及基本数据类型和引用数据类型的存储方式。接着说明赋值时基本类型和引用类型的不同表现,浅拷贝和深拷贝的原理、实现方法及注意事项,如浅拷贝可通过Object.assign等实现,深拷贝可通过JSON.parse/stringify或lodash库实现。
相关理解
  • 堆和栈
    堆和栈是内存中划分出来用来存储的区域。栈为自动分配的内存空间,由系统自动来释放;而堆则是动态分配的内存,大小不定且不会自动释放。

  • ECAMScript数据类型

    • 基本数据类型: string, number boolean symbol null undefined
      存放在栈内存中,基本数据类型的数据大小确定,内存空间大小可以分配,是直接按值存放的,所以可以直接访问
      基本数据类型值不可变,两个基本类型之间的比较就是值的比较
    • 引用数据类型: String Number Boolean Object Function Array Date RegExp Error
      存放在堆内存中,变量实际上是一个存放在栈内存中的指针,指针指向了堆内存中的地址。大小不同,需要动态分配。
      引用数据类型的值是可以改变的,其比较是引用的比较,即看其引用是否指向了同一个对象

    注意:闭包中的变量存在在堆内存中而非栈内存中。

赋值与浅拷贝
  • 赋值
    1.当基本数据类型进行赋值操作的时候,是在内存中开辟了一个新的栈内存,然后再把值赋值到新的栈内存中,因此基本类型赋值的两个变量是相互独立互不影响的。

    2.引用数据类型的赋值是传址,顾名思义就是说是对于对象保存在栈内存中的堆内存地址进行赋值,由此,两个变量就指向了同一个对象,因此其中一个改变,另外一个必将受到影响。

  • 浅拷贝:
    创建一个新对象,这个新对象有着原始对象属性值的一份精确拷贝
    实例:

    1. Object.assign(target, …sources)实现对对象的浅拷贝
      target: 拷贝的目标 sources:源对象【可以为多个对象】
      注意:
      • 只拷贝源对象的自身属性,不拷贝继承属性
      • 不会拷贝对象不可枚举的属性
      • undefined和null不可作为target, 可以作为source
      • 属性名为Symbol的属性是可以被object.assign拷贝的
    2. Array.prototype.slice实现对数组的浅拷贝
    3. Array.prototype.concat将数组和数组或和值连接在一起成新的数组
    4. …扩展运算符

    实现浅拷贝
    原理:新的对象复制已有对象中非对象属性的值和对象属性的引用。

    function shadowClone(sources) {
    	var target = {};
    	for (var key in sources) {
    		if(Object.prototype.hasOwnProperty.call(sources, key)) {
    			target[key] = source[key];
    		}
    	}
    	return target;
    }
    
  • 深拷贝:
    会拷贝一份一模一样的对象,从堆内存中开辟一个新的区域存放新对象,新对象与原对象不共享内存,修改新的对象不会改变原对象。

    实例:

    1. JSON.parse()/JSON.stringify()
      JSON.stringify()把一对象序列化成一个json字符串,将对象的内容转换成字符串的形式再保存在磁盘上,在用JSON.parse()反序列化JSON字符串成为一个新的对象。【不可处理函数】
      注意:
      • 拷贝的对象中存在函数,undefined,symbol则经过JSON.stringify()序列化后的字符串中这个键值会消失
      • 无法拷贝不可枚举的属性,无法拷贝对象的原型链
      • 拷贝Date引用类型会变成字符串
      • 拷贝RegExp引用类型会变成空对象
      • 对象中含有NaN、Infinity和-Infinity,则序列化的结果会变成null
      • 无法拷贝对象的循环应用(即obj[key] = obj)
    2. 第三方深拷贝库lodash中_.cloneDeep()

    实现深拷贝
    原理:运用递归思想,遍历对象和数组直到里面所有为基本数据类型,然后再去复制。

    //定义检测数据类型的功能函数
    function isObject(obj) {
    	return typeof obj === Object && obj !== null;
    }
    
    function cloneDeep(source) {
    	if (!isObject(source)) {
    		return source;
    	}
    	var target = Array.isArray ? [] : {};
    	for (var key in source) {
    		if (Object.prototype.hasOwnProperty.call(source, key){
    			if (isObject(source[key])) {
    				target[key] = cloneDeep(source[key]);//无法处理源对象内部循环引用的问题。
    			} else {
    				target[key] = source[key];
    			}
    		})
    	}
    }
    
赋值、浅拷贝与深拷贝区别:
操作和原数据是否指向同一对象第一层数据为基本数据类型原数据中包含子对象
赋值改变使原数据一同改变改变使原数据一同改变
浅拷贝改变不会使原数据一同改变改变使原数据一同改变
深拷贝改变不会使原数据一同改变改变不会使原数据一同改变
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值