一、数据类型
JavaScript有lia两种数据类型:
1.基本数据类型:Number、String、Undefined、Null、Boolean、Symbol。这六种数据类型数据段简单,大小可以确定,存放在栈中,是直接按值存放的,也可以直接访问。
2.引用类型:如对象、数组等。这些对象的大小不一定,是存放在堆中的,其在栈中的值只是一个指向堆的指针。
二、引发的问题
1.复制基本类型数据时,栈的值可以直接引用。
2.复制引用类型数据时,栈的值只是一个指向堆的指针,当改变其中一方的值时,另外一方的值也会跟着改变。
如下:
let a = 'hi';//基本数据类型,在栈中的值可以直接引用
let b = [1, 2, 3];//数组,在栈中的值是指向堆的指针
let c = a;//复制 a
let d = b;//复制 b
console.log('第一次的a: ', a)
console.log('第一次的b: ', b)
console.log('第一次的c: ', c)
console.log('第一次的d: ', d)
c = 'hi-hi';//复制基本类型的值,修改不会影响其他变量。
d.push(4); //复制引用类型的值,修改时都有影响
console.log('--------------')
console.log('第二次的a: ', a)
console.log('第二次的b: ', b)
console.log('第二次的c: ', c)
console.log('第二次的d: ', d)
可以看到,d是复制b(引用类型),当向d中插入数据时,b的数据也是变化的。因为b只是复制了d在栈中指向堆的指针,也就是b和d是共用一个堆的,不管哪一方修改,两者的值都是同步改变。
三、浅拷贝
通过上面可以得出,如果我们拷贝一个引用类型,我们两者互不影响,那就应该新开辟一个堆来存放,而不是只拷贝在栈中指向堆的指针。
浅拷贝,网上很多都说是只拷贝一层,意思大概如下:
let e = {
name: '浅拷贝',
arrys: [11,22,33]
}
function copySimple (obj){
let newObj = {}
newObj.name = obj.name;
newObj.arrys = obj.arrys;
return newObj;
}
let f = copySimple(e);
console.log('--------------')
console.log('第一次浅拷贝的e: ', e)
console.log('第一次浅拷贝的f: ', f)
f.name = '浅拷贝,修改';
f.arrys.push(44);
console.log('--------------')
console.log('第二次浅拷贝的e: ', e)
console.log('第二次浅拷贝的f: ', f)
对象e中存在一个数组值,我们的函数 copySimple 通过获取e对象的每一个值,返回一个新的对象,这样子我们拷贝的就不是edui'对象在zha栈中指向堆的指针,而是直接到堆中找相应的值。这里有两种qing情况:
像e.name 的值是一个String(基本数据类型),其值可以直接引用。而像e.arras 的值是一个数组(引用类型),此时拷贝出来的arrys值又是一个指向堆的指针。所以当我们在 f.arrys 中插入一个值时,照样会改变 e 对象中 arrys的值。这就是浅拷贝,没有把对象的对象再进行遍历到成为基本类型就进行赋值。
四、深拷贝
深拷贝网上很多说是多层拷贝,就是通过将对象中的每一个对象值进行遍历,使其成为基本数据类型再进行拷贝,这样拷贝出来的对象的值就完全是存放在另一个堆中,拷贝对象的数据变化也不会对其产生影响。如下:
let g = {
name: '深拷贝',
arrys: [11,22,33]
}
function coypDeep(obj){
let newObj = {}
if(obj.name){
newObj.name = obj.name;
}
if( obj.arrys ){
let newArrys = [];
for(let val of obj.arrys){
newArrys.push(val)
}
newObj.arrys = newArrys;
}
return newObj;
}
let h = coypDeep(g);
console.log('--------------')
console.log('第一次深拷贝的g: ', g)
console.log('第一次深拷贝的h: ', h)
h.name = '深拷贝,修改';
h.arrys.push(44);
console.log('--------------')
console.log('第二次深拷贝的g: ', g)
console.log('第二次深拷贝的h: ', h)
coypDeep函数将 g.arrys 数组遍历了一遍,成为基本数据类型。当我们再次改变 复制出来的 h,arrys 的值时,原来的对象 g 中的 arrys 值也不会改变。
五、实现深拷贝几种方法
1.通过 JSON.stringify()将对象字符串化,再进行拷贝。
2.[...obj],通过es6扩展运算符将对象都列成基本数据类型再赋值。
3.Array.from()可以将数组重新zhu转成数组再赋值。
......