1.前言:数据类型
数据类型分为基本数据类型和引用数据类型,理解这两种数据类型的特点,对理解深拷贝和浅拷贝至关重要
1.1 基本数据类型
基本数据类型:Boolean、Null、Undefined、Number、String、BigInt、Symbol
基本数据类型都是存储在栈(stack)内存中,栈具有先进后出的特点,基本数据类型占用空间小、大小固定,通过按值来访问,属于被频繁使用的数据。
let a=1;
let b=a;
a=3;
console.log(a,b)
输出结果:
基本数据类型的赋值,赋值后两个变量互不影响,b复制的是a的原始值,它们存储在独立的的栈空间中,因此修改了的值,b的值不会受到影响
1.2 引用数据类型
引用数据类型:Object(包括 Object 、Array 、Function)
引用数据类型占据空间大、大小不固定,存放在栈中会有性能的问题。引用数据类型在栈中保存了一份指针,该指针指向对应的数据在堆中的起始地址,当解释器寻找引用值时,会首先检索其在栈中的地址,通过地址从堆中获得数据。
obj={
age:21
}
let objCopy=obj;
objCopy.age=22;
console.log(obj,objCopy)
引用类型的赋值,在栈中复制了一份引用类型的地址指针,两个变量指向的还是同一个对象,所以修改objCopy.age时,obj.age也会改变
2.浅拷贝和深拷贝
2.1 浅拷贝
浅拷贝是指,一个新的对象对原始对象的属性值进行精确地拷贝,如果拷贝的是基本数据类型,拷贝的就是基本数据类型的值,如果是引用数据类型,拷贝的就是内存地址。如果其中一个对象的引用内存地址发生改变,另一个对象也会发生变化。
实现浅拷贝
- Object.assign()
Object.assign() 是ES6中对象的拷贝方法,接受的第一个参数是目标对象,其余参数是源对象,用法: Object.assign(target, source_1, ···) ,该方法可以实现浅拷贝,也可以实现一维对象的深
拷贝。
let target={a:1}
let object1={b:2,c:3}
Object.assign(target,object1)
console.log(target)//{a:1,b:2,c:3
- 扩展运算符
let obj1 = {a:1,b:{c:1}}
let obj2 = {...obj1};
obj1.a = 2;
console.log(obj1); //{a:2,b:{c:1}}
console.log(obj2); //{a:1,b:{c:1}}
- 手写实现浅拷贝函数
// 浅拷贝的实现;
function shallowCopy(object) {
// 只拷贝对象
if (!object || typeof object !== "object") return;
// 根据 object 的类型判断是新建一个数组还是对象
let newObject = Array.isArray(object) ? [] : {};
// 遍历 object,并且判断是 object 的属性才拷贝
for (let key in object) {
if (object.hasOwnProperty(key)) {
newObject[key] = object[key];
}
}
return newObject;
}
2.2 深拷贝
深拷贝相对浅拷贝而言,如果遇到属性值为引用类型的时候,它新建一个引用类型并将对
应的值复制给它,因此对象获得的一个新的引用类型而不是一个原有类型的引用,所以彼此的修改,互不影响。
- JSON.stringify()
JSON.parse(JSON.stringify(obj)) 是目前比较常用的深拷贝方法之一,它的原理就是利用JSON.stringify 将 js 对象序列化(JSON字符串),再使用 JSON.parse 来反序列化(还原) js 对
象。这个方法可以简单粗暴的实现深拷贝,但是还存在问题,拷贝的对象中如果有函数,undefined,symbol,当使用过 JSON.stringify() 进行处理之后,都会消失。
let obj2={
a:1,
b:{
c:2
}
}
let obj3 = JSON.parse(JSON.stringify(obj2));
obj2.b.c=3;
console.log(obj2)//{a:1,b:{c:3}}
console.log(obj3)//{a:1,b:{c:2}}
- 函数库lodash的_.cloneDeep方法
var _=require('lodash')
let obj2={
a:1,
b:{
c:2
}
}
var obj4=_.cloneDeep(obj2);
console.log(obj2.b===obj4.b)//false
- 手写实现深拷贝函数
// 深拷贝的实现
function deepCopy(object) {
if (!object || typeof object !== "object") return;
let newObject = Array.isArray(object) ? [] : {};
for (let key in object) {
if (object.hasOwnProperty(key)) {
newObject[key] =typeof object[key] === "object" ? deepCopy(object[key]) : object[key];
}
}
return newObject;
}