平时编程时,少不了要进行赋值操作,赋值意味着着要进行拷贝,但是由于js的数据类型不同,导致拷贝方式不同,结果也不就同。
具体的数据类型包括:
基本类型(Number,String,Boolean,Null,Undefined ,Symbol ):存放于栈内存;
引用类型(Object):存放与堆内存。
基本类型的数据进行拷贝时,只需要将具体的值进行复制,拷贝到对应新变量中去即可;但是,对于引用类型的数据,复制意味着只是将引用类型的数据地址复制被复制给新的变量,最终的结果就是两个变量指向同一个在堆内存中的对象,改变一个,另外的一个对象也会发生变化。因此,对于复制拷贝有了两种方式:浅拷贝,深拷贝。
浅拷贝
将对象的各个属性进行依次复制,不会递归复制。当对于目标对象第一层为基本数据类型的数据,就是直接赋值,即「传值」;而对于目标对象第一层为引用数据类型的数据,就是直接赋存于栈内存中的堆内存地址,即「传址」,并没有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变。
//浅拷贝==》复制对象所有属性都不是引用类型
//遍历并复制,返回新对象
//浅拷贝会复制所有的引用对象的指针,而不是具体的值
function shallowCoyp(obj){
var coyp={};
for(key in obj){
if(obj.hasOwnProperty(key)){//只复制本身拥有的属性
coyp[key]=obj[key];
}
}
return coyp;
}
深拷贝
对浅拷贝的进一步改进。
1、粗暴方式:JSON.parse(JSON.stringify(obj))
缺点:
- undefined、任意的函数、正则表达式类型以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时);
- 它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object;
- 如果对象中存在循环引用的情况无法正确处理
2、其他
//深拷贝==》复制拥有所有的属性和方法的新对象
//粗暴方式:JSON.parse(JSON.stringify(obj))
//缺点:
//1 undefined、任意的函数、正则表达式类型以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时);
//2 它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object;
//3 如果对象中存在循环引用的情况无法正确处理
function deepCopy1(obj){
if(typeof obj!='object'){
return obj;
}else{
var newobj={};
for(var oo in obj){
newobj[oo]=deepCopy1(obj[oo]);
}
return newobj;
}
}
// ||||对象引用循环???
//解决循环引用
var hasarr = [];
function deepCopy2(obj) {
let copy = {};
hasarr.push(obj);
for (let i in obj) {
if (typeof obj[i] === 'object') {
let index = hasarr.indexOf(obj[i]);
if (index > -1) {
// 引用了相同对象,那么无论是循环引用还是重复引用,我们返回引用就可以了
copy[i] = hasarr[index];
} else {
copy[i] = deepCopy2(obj[i]);
}
} else {
copy[i] = obj[i];
}
}
return copy;
}