JavaScript的数据类型
JS中有7种数据类型:String、Number、Boolean、Null、Undefined、对象以及ES6新增的Symbol。 由于目前还未深入了解过Symbol,所以此次不讨论Symbol。 其中6种为基本类型(或叫做简单数据类型)和1种引用类型(复杂数据类型)。
- 基本类型
- String
- Number
- Boolean
- Null
- Undefined
- 引用类型
- 对象
不同数据类型在内存中如何存储?
我们将内存分为栈(Stack)内存和堆(Heap)内存 基本类型以固定大小的空间存在与栈内存中,当基本类型发生值的拷贝时,目标变量会得到原始变量的值的副本。
let a = 1
let b = a //1
引用类型的值是对象,保存在堆内存中,引用类型的变量的值并不是值的本身,而是这个值在堆内存中的地址(也有说法为指针,不过我个人觉得地址容易理解)。当引用类型发生值的拷贝的时候,实际上目标变量得到的是原始变量的值的地址。
let obj1 = {
name: "jack"
}
/*
此时{name: "jack"}这个对象存在于堆内存中,我们假设他的地址是218
*/
let obj2 = obj1 //在这个赋值操作中,传递的其实是对象在内存中的地址
浅拷贝
let data = {
name: "jack",
age: 18,
gender: "male"
}
let copyDate = data
copyDate === data //true
copyDate.name = "Tom"
copyDate.name === data.name //true
copyDate === data //true
上面这段代码就是一个浅拷贝的例子,由此可见,浅拷贝就是目标变量得到原始变量的值后, 不管是目标变量还是原是变量,只要值发生变化,那么两个变量都会收到影响。这一点从内存图中就可以看出,因为引用地址相同。
深拷贝
let a = 1
let b = a
b = 2
a //1
变量b得到变量a的值,但变量b的值改变,不影响变量a,这就是深拷贝
存在的问题 & 解决方法
有些时候,我们需要深拷贝一个对象或者数组,但=
操作符只能实现浅拷贝
对象的深拷贝
//最容易想到的方法:遍历原始对象
let obj = {
name: "jack"
}
let copyObj = {}
for(let key in obj){
copyObj[key] = obj[key]
}
obj === copyObj //false
//使用JSON
let a = {name: "alex"}
let b = JSON.parse(JSON.stringify(a))
//ES6的方法
let source = {
name: "Tom",
age: 18
}
let target = Object.assign({}, source)
//Object.assign方法用于将原始对象的所有可枚举属性复制到目标对象上。
target === source //false
数组的深拷贝
//最简单的方法还是遍历数组,这里就不多讲
//其次我们可以用到Array的方法,比如map、slice等可以返回新数组的方法
let a = [1,2,3,4]
let b = a.map(n => n)
let c = a.slice()
a === b || a === c //false