前言
本文先给出值类型跟引用类型的区别列出哪些是值类型哪些是引用类型以及它们在内存中如何存放的,再聊聊计算机为什么需要引用类型,最后对引用类型实现深拷贝。
值类型跟引用类型
javascript中值类型跟引用类型有:
值类型: number
, string
, boolean
, symbol
, undefined
引用类型: object
, null
, array
它们的区别在于应用跑起来时在内存中的存放方式不同,值类型变量的数据直接存放在栈区,引用类型的变量数据存放在堆区(这个堆跟数据结构中的堆不是一个东西), 通过一个地址来实现对数据的引用:
let obj1 = 'liaowei'
let obj2 = {
name: 'liudehua',
age: 60
}
let obj3 = obj2
let obj4 = obj1
obj3.age = 20
obj4 = 'guofucheng'
console.log(obj1) // liaowei
console.log(obj2.age) // 20
console.log(obj3.age) // 20
console.log(obj4.age) // guofucheng
代码运行后在内存中的模型图:
可见obj2、obj3两个引用类型指向的都是堆中的一个数据,所以对obj3进行修改后obj2也相应的发生了变化,而obj1、obj4都是值类型直接存储在栈区中因此两者并不存在引用关系。
程序为什么要区分堆区跟区呢?
因为引用类型的数据量比较大,频繁赋值对性能有影响所以将其存放在堆中赋值时使用浅拷贝直接引用,如果用户有需要可以手动进行深拷贝。
深拷贝
1.递归实现深拷贝
function deepCopy(obj) {
if(typeof obj !== 'object' || obj === null) {
return obj
}
let result
if(obj instanceof Array) {
result = []
} else {
result = {}
}
for(key in obj) {
result[key] = deepCopy(obj[key])
}
return result
}
该函数有两个return语句,一个返回值类型的值,一个返回引用类型的值,如果当前考察的对象是引用类型,对其属性进行遍历调用自身实现递归,如果当前考察对象是一个值类型直接反回其本身结束递归。
2.使用JSON.stringify实现深拷贝
let obj2 = JSON.parse(JSON.stringify(obj1))
使用stringify方法先将对象转换成JSON字符串,再将字符串解析成一个新的JSON对象,这种方法如果对象中存在函数或是undefined,则序列化的结果会把函数或undefined丢失。