数据类型分为基本数据类型和引用数据类型,理解这两种数据类型的特点,对理解深拷贝和浅拷贝至关重要
基本数据类型:Boolean、Null、Undefined、Number、String、BigInt、Symbol
基本数据类型都是存储在栈(stack)内存中,栈具有先进后出的特点,基本数据类型占用空间小、大小固定,通过按值来访问,属于被频繁使用的数据。
let a=1;
let b=a;
a=3;
console.log(a,b)
输出结果:
基本数据类型的赋值,赋值后两个变量互不影响,b复制的是a的原始值,它们存储在独立的的栈空间中,因此修改了的值,b的值不会受到影响
引用数据类型:Object(包括 Object 、Array 、Function)
引用数据类型占据空间大、大小不固定,存放在栈中会有性能的问题。引用数据类型在栈中保存了一份指针,该指针指向对应的数据在堆中的起始地址,当解释器寻找引用值时,会首先检索其在栈中的地址,通过地址从堆中获得数据。
obj={
age:21
}
let objCopy=obj;
objCopy.age=22;
console.log(obj,objCopy)
引用类型的赋值,在栈中复制了一份引用类型的地址指针,两个变量指向的还是同一个对象,所以修改objCopy.age时,obj.age也会改变
浅拷贝是指,一个新的对象对原始对象的属性值进行精确地拷贝,如果拷贝的是基本数据类型,拷贝的就是基本数据类型的值,如果是引用数据类型,拷贝的就是内存地址。如果其中一个对象的引用内存地址发生改变,另一个对象也会发生变化。
实现浅拷贝
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;
}
深拷贝相对浅拷贝而言,如果遇到属性值为引用类型的时候,它新建一个引用类型并将对
应的值复制给它,因此对象获得的一个新的引用类型而不是一个原有类型的引用,所以彼此的修改,互不影响。
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}}
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;
}