js数据类型有哪些,深拷贝与浅拷贝的区别,堆与栈的区别,一篇文章带你搞清楚
学习js的深拷贝和浅拷贝之前,我们先回顾一下js的数据类型有哪些和堆与栈的知识。
js的数据类型
js的数据类型分为基本数据类型和引用数据类型。
基本数据类型有:String、Number、Boolean、Symbol、Undefined、Null
引用数据类型有:Object、Array、function
堆与栈
栈(stack)为自动分配的内存空间,它由系统自动释放;而堆(heap)则是动态分配的内存,大小不定也不会自动释放。
基本数据类型数据存放在栈中:存放在栈内存中的简单数据段,数据大小确定,内存空间大小可以分配,是直接按值存放的,所以可以直接访问。
基本数据类型值不可变:基本数据类型的值是不可变的,动态修改了基本数据类型的值,它的原始值也是不会改变的
例如:
引用类型数据存放在堆中:引用类型(object)是存放在堆内存中的,变量实际上是一个存放在栈内存的指针,这个指针指向堆内存中的地址。每个空间大小不一样,要根据情况开进行特定的分配
引用数据类型值可变:
总结就是,内存分为堆和栈,它们是存储数据的不同区域,堆存放引用数据类型的数据,栈存放基本数据类型的数据。
传值与传址
在我们进行赋值操作的时候,基本数据类型的赋值(=)是在内存中新开辟一段栈内存,然后再把再将值赋值到新的栈中。
所以说,基本类型的赋值的两个变量是两个独立相互不影响的变量,这就是基本数据类型的传值。但是引用类型的赋值是传址。只是改变指针的指向,例如,也就是说引用类型的赋值是对象保存在栈中的地址的赋值,这样的话两个变量就指向同一个对象,因此两者之间操作互相有影响。
浅拷贝
其实上面的代码是我们常用的赋值引用,还不能算浅拷贝。赋值和浅拷贝有何区别?
obj1 原始数据,obj2 赋值数据,obj3 浅拷贝数据。为什么改变了赋值得到的对象 obj2 和浅拷贝得到的 obj3 中的 language) 属性的第二个值和第三个值(language 是一个数组,也就是引用类型)。结果见输出,可以看出来,无论是修改赋值得到的对象 obj2 和浅拷贝得到的 obj3 都会改变原始数据。因为浅拷贝只复制一层对象的属性,并不包括对象里面的为引用类型的数据。所以就会出现改变浅拷贝得到的 obj3 中的引用类型时,会使原始数据得到改变。
用一句话简单理解 :浅拷贝就是拷贝了一层,除了对象是拷贝的引用类型,其他(一开始讲到的基本数据类型)都是直接将值传递,有自己的内存空间的。
深拷贝:将 B 对象拷贝到 A 对象中,包括 B 里面的子对象。
浅拷贝:将 B 对象拷贝到 A 对象中,但不包括 B 里面的子对象。
深拷贝
看完对浅拷贝的理解,可以知道:深拷贝就是对对象以及对象的所有子对象进行拷贝。深拷贝与浅拷贝针对的是引用数据类型而言,比如对象,数组,函数这些引用数据类型都有深拷贝与浅拷贝。基本数据类型,如数字,字符串是无深拷贝和浅拷贝一说的,那么如何对对象进行深拷贝?
1、用 JSON.stringify 把对象转成字符串,再用 JSON.parse 把字符串转成新的对象(使用JSON)。
坏处:它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。所以只适合 Number, String, Boolean, Array 的扁平对象。
2、递归拷贝
或者使用es6中的 Object.create()方法