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