基本类型&引用类型
JavaScript中数据类型可以分为两类:基本类型和引用类型
- 基本类型:string,number,symbol,undefined,null,Boolean
- 引用类型:Array,Function,Object,Date
基本数据类型保存在栈内存中,有固定的内存空间大小存储;而引用类型保存在堆内存中,它存放的是变量在堆中的内存地址,这个地址指向的是数据。
因为基本类型有可以计算出固定的大小,可以合理的分配合适大小的内存空间,所以它被保存在栈中;而函数,数组这一类数据定义了,函数可以无限扩展,数据可以无限添加,无法确定其大小空间,所以被保存在堆中,通过地址链接到这个数据.这里我们就可以知道在浅拷贝中如果复制出来的数据修改了值,那么原始的值也会改变,因为我们浅拷贝就是复制了对这个数据的引用地址,而不是真正的开辟内存空间保存这个数据.
浅拷贝
现在我们知道了如果一个数据不是引用类型,我们就可以通过浅拷贝的方法.
var person = "tom"
var newperson = person
我们针对基本的数据类型通过赋值操作就是能直接拷贝,那么如果是引用类型里浅拷贝呢?
var person = {
name: "tom",
age: 18,
hobby: {
num: 3
}
}
//上面我们定义了一个person,我们可以用遍历的方式来进行浅拷贝
function copy(obj){
var newobj = {}//定义新的对象接受
for(key in obj){
//只复制它背身有的属性
newobj[key] = obj[key]
}
return newobj
}
//我们定义了一个copy函数
var newperson = copy(person)
通过上面循环的方式我们就完成了一个对象的浅拷贝,当我们修改新对象上的age属性时,原对象的age不会改变;但是当我们修改hoobby中num属性时,原对象的num同样也就修改了.
当有深层的引用类型时,我们通过浅拷贝无法满足我们的需求,因为它仅仅是拷贝了一个引用的地址,实际新旧两对象是指向的同一个数据,当其中一个数据修改,另一个数据也体现出来了.那我们再看下深拷贝.
深拷贝
深拷贝我们一般常用的有两种,JSON和递归
JSON方式
var person = {
name: "tom",
age: 18,
hobby: {
num: 3
}
}
var newperson = JSON.parse(JSON.stringify(person))
我们先通过JSON.stringify()
方式将对象先转换为字符串,再通过JSON.parse()
转换为对象.这个方法虽然好用,但也有它的不足.
var person = {
a: undefined,
b:null,
c:function(){
alert("1")
},
name: "tom",
age: 18,
hobby: {
num: 3
}
}
var newperson = JSON.parse(JSON.stringify(person))
上面我们定义了a,b,c三个属性,通过打印结果看来,undefined
和function
,都被过滤掉了.虽然它有不足,但在日常使用中已经足够了.
递归的方法
var person = {
a: undefined,
b:null,
c:function(){
alert("1")
},
name: "tom",
age: 18,
hobby: {
num: 3
}
}
function deepcopy(obj){
var newobj = null
//定义变量用来存贮拷贝后的内容
if(typeof obj === "object" && obj !== null){
//先判断下拷贝的函数是不是对象并且不为null
newobj = obj instanceof Array? []: {}
//判断是数组还是对象,复制
for(var i in obj){
循环遍历每一项,直到没有复杂数据类型
newobj[i] = deepcopy(obj[i])
}
}else{
newobj = obj
}
return newobj
}