1.JS的数据类型
- 基本数据类型:Number、String、Boolean、Null、undefined、Symbol
- 复杂数据类型:Object(除上述基本数据类型以外的数据类型,也称为引用数据类型)
2.栈(stack)和堆(heap)
- 栈:自动分配的内存空间,由系统自动释放
- 堆:动态分配内存,大小不定,不会自动释放
在 **JS **中基本数据类型存放在栈中,复杂数据类型(引用数据类型)的数据地址存放在栈中,而地址指向的数据则存放在堆中。
3.基本数据类型的复制
JS中的基本数据类型的值都有固定的大小,保存在栈内存中,由系统自动分配存储空间在栈内存空间的值,我们可以直接进行操作,所以基础数据类型都是按照值访问。
在栈内存中的数据发生复制的行为时,系统会自动为新变量开辟一个新的内存空间,当复制执行后,两个内存空间的值就互不影响,改变其中一个不会影响另一个。
也就是说两个变量的值虽然相同,但是地址不同,所以其中一个变量值的改变,并不会引起和影响到另一个变量值的变化。
基本数据类型是通过赋值进行复制的。
var a = 10
var b = a
b = 20
console.log(a); //10
console.log(b); //20
console.log(a === b); //False
4.复杂数据类型的复制
复杂数据类型是把变量的地址存储在栈内存里,把变量的值存储在堆内存里面,在JS中我们不能直接操作对象的堆内存空间,又因为复杂类型的值都是按引用(地址)访问的,所以在操作复杂数据时,实际上是操作复杂数据的引用(地址)而不是实际的值。复杂数据类型的复制有赋值和拷贝两种。
赋值:两个变量的地址都指向了同一个对象,改变其中一个,另一个也会受到影响。即赋值时栈内存会开辟一个新空间,用来存放新的变量和新变量的地址,堆空间内并不会为新变量开辟新的空间,所以赋值时,两个变量的内存地址相同,且指向同一个空间。可以理解为一个房间的两把钥匙。
var a = [1,[2,3],[4,[5,6,[7,8]]]]
var b = a
b[2][1][2][1] = 10
console.log(a); //[1,[2,3],10,5,6]
console.log(b); //[1,[2,3],10,5,6]
console.log(a === b); //True
拷贝:是复杂数据类型通过复制生成一个新的对象(新的数据)。解决了复杂数据类型复制中一个数据的改变影响另一个数据的问题。拷贝又分为浅拷贝与深拷贝。
浅拷贝:在堆内存中开辟了一个新空间,拷贝后新对象获得一个独立的基本数据类型数据,和原对象共用一个原对象内的引用类型数据,改变基本类型数据,两个对象互不影响,改变其中一个对象内的引用类型数据,另一个对象会受到影响。即浅拷贝后,新对象内的基本数据类型与原数据的内存地址不同,新对象内的复杂数据类型与原数据的内存地址相同。
var a = [1,[2,3],4,5,6]
var b = [...a]
b[1][1] = 300
b[0] = 100
console.log(a); //[1,[2,300],4,5,6]
console.log(b); //[100,[2,300],4,5,6]
console.log(a === b); //False
深拷贝:在堆内存空间中重新开辟了一个空间,拷贝后的新对象是一个对立的数据,因为不论是对象内的基本类型还是引用类型都被完全拷贝,拷贝后两个对象互不影响。即新对象内的数据类型与原数据,无论基本数据类型还是复杂数据类型的内存地址都不相同。
function deepCopy(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
let copy = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopy(obj[key]);
}
}
return copy;
}
let obj = { a: 1, b: { c: 2 } };
let copy = deepCopy(obj);
console.log(copy); // { a: 1, b: { c: 2 } }
复杂数据类型复制总结:
赋值:新对象与原对象的内存地址一样,无论是改变任一对象的基本数据类型还是复杂数据类型,都会影响另一个对象。
浅拷贝:新对象中只有复杂数据类型的内存地址与原对象的内存地址相同所以改变新对象基本类型的值不会使原对象对应的值一起改变,但是改变新对象引用类型的值会使原对象对应的值一同改变。
深拷贝:新对象的基本数据类型和复杂数据类型的的内存地址与原对象的内存地址都不相同,两者互相独立,互不影响。所以任一对象的数据改变都不会影响另一对象。
注意:
1.基本数据类型的复制可以理解为深拷贝。
2.复杂数据类型的复制,复制后数据的内存地址相同,则会相互影响,内存地址不同就不会影响。