数据类型
数据类型
在JavaScript中,数据类型有两大类。一类是基本数据类型,一类是引用数据类型。
基本数据类型有六种:number、string、boolean、null、undefined、symbol。
基本数据类型存放在栈中。存放在栈中的数据具有数据大小确定,内存空间大小可以分配、直接按值存放的特点。所以存放在栈中的数据可以直接访问。在JavaScript中,基本数据类型的值是直接存放在变量访问的地方,而且是按值存储。基本的数据类型值是不可更改的。我们在修改字符串或其他基本数据类型变量时,实际上是返回了一个新的值,而不是【改变】原始值。
而对于引用数据类型(Object、Array),是存放在堆内存中。引用数据类型的变量并不是存放的实际值,而是一个存放在栈内存的指针,该指针指向堆内存中的某个地址。每个数据所占的空间大小不一致,需要根据情况进行特定的分配。与基本数据类型不同,引用类型的值是可以改变的。在JS中,引用数据类型的变量是存储在 内存中的对象,变量本身存储的是 该对象的引用内存地址。
赋值
对于基本数据类型来说,当我们进行赋值操作(=)时,实际上是在内存中新开一段栈内存,然后再将值赋值到新的栈中。——传值,且两者之间互不影响
对于基本数据类型来说,赋值操作是给了一个全新的栈,所以a、b之间后续是互不影响的。
然而对于引用数据类型来说,赋值操作实际上是把变量的地址传给了另一个变量,所以称为传址。传址之后,两个变量就指向同一个地址,两者的操作是互有影响的。
例:
深浅拷贝
注意:对于基本数据类型,深浅拷贝没有区别
对于引用数据类型,才存在深浅拷贝之分
浅拷贝
浅拷贝就是指创建一个新对象,该对象拥有原始对象第一层属性的精确拷贝。如果原始对象还嵌套了其他对象,浅拷贝是不会拷贝的。
即:如果原始对象的属性是基本类型数据,则拷贝的就是基本数据类型的值;如果原始对象的属性是引用类型,则拷贝的是内存地址。
注意:当原始对象的引用类型属性发生改变时,拷贝对象的对应属性值也会发生变化。
这里需要强调一下,浅拷贝与赋值是有所区别的,赋值时与原数据指向同一对象,而浅拷贝则指向了不同对象。
在JavaScript中,存在浅拷贝的现象有:
· 利用Object对象自带的一些方法,例如Object.assign
· Array.prototype.slice(), Array.prototype.concat()
· 使用拓展运算符(…)实现的复制
深拷贝
浅拷贝是对原始对象第一层属性的精确拷贝,而深拷贝则是对原始对象所有层级属性的递归精确拷贝。
浅拷贝应用于需要对进程进行快照、复位或操作的情景;
深拷贝适用于需要在副本中做出更改而不影响原始对象的情况。
深拷贝开辟一个新的栈,两个对象的属性完全相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。在拷贝对象的时候,创建一个新的对象,并将原始对象的所有属性和嵌套对象等数据复制到新对象中,而不是对原始对象的引用进行复制。
实现方法:
(1)使用JSON方法实现深拷贝。先利用JSON.stringfy()要深拷贝的对象转换成JSON格式的字符串,然后再使用JSON.parse()把JSON字符串转换成新的对象,但是该方法存在一些局限性。比如它们无法处理特殊的对象类型(如Date),无法处理循环引用,也无法处理对象属性中的函数。
(2)如果出现了JSON方法无法深拷贝的对象,可以使用第三方库来实现,比如Lodash和jQuery等,这些库内部都实现了深拷贝方法
总结
对于引用数据类型(即对象Object)来说:
这里最迷惑的点之一就是要注意:
· 如果一个变量是Object类型,且它的第一层数据为基本数据类型的时候,你用浅拷贝,那么拷贝后再去改变拷贝对象,是不会影响原数据的!!!如果用赋值就会影响。