文章目录
前言
在正式内容开始前,我们要对栈(stack)、堆(heap)、基本数据类型、引用数据类型有基本的了解。
想必基本数据类型与引用数据类型大家已经不陌生了,这里就不过多介绍了。
栈:自动分配内存空间,系统自动释放。里面存放的是基本数据类型的值和引用数据类型的地址。
堆:动态分配的内存,大小不定,不会自动释放。里面存放的是引用数据类型的值。
一、浅拷贝是什么?
浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。即对象的浅拷贝会对“主”对象进行拷贝,但不会复制主对象里面的对象。“里面的对象”会在原来的对象和它的副本之间共享。
示例:
//基本数据类型Number
var a=1;
var b=a;
//b=1
b=2;
//b=2
//a=1
//数组
var arr1 = [1,2,3];
var arr2 = arr1;
//arr2=[1,2,3]
arr2.push(4);
//arr2=[1,2,3,4]
//arr1=[1,2,3,4]
//对象
var obj1={count:1,name:'grace',age:1};
var obj2 = obj1;
//obj2={count:1,name:'grace',age:1}
obj2.count=2;
//obj1={count:2,name:'grace',age:1}
//obj2={count:2,name:'grace',age:1}
综上所述,得出两点:
1、如果是基本数据类型,直接进行赋值操作,这样就相当于在栈内存中重新开辟了一个新的空间把值传递过去。
2、如果是引用类型的值传递,进行的就是浅拷贝,浅拷贝赋值的只是对象的引用。
如上述obj2=obj1,实际上传递的只是obj1的内存地址,所以obj2和obj1指向的是同一个内存地址,所以这个内存地址中值的改变对obj1和obj2都有影响。
二、深拷贝
深拷贝:深拷贝不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上,所以对一个对象的修改并不会影响另一个对象。
以下分了两种数组和对象
数组
1.for循环
var arr1 = [1,2,3];
var arr2 = copyArr(arr1);
function copyArr(arr){
var res=[];
for(var i=0,length=arr.length;i<length;i++)
{
res.push(arr[i]);
}
return res;
}
2.slice()
var arr1 = [1,2,3];
var arr2 = arr1.slice(0);
3.concat()
var arr1 = [1,2,3];
var arr2 = arr1.concat();
4.JSON.stringify()
jQuery深拷贝 var copiedObject = $.extend(true, {}, originalObject)
JSON.stringify:将一个js值转为json字符串
var array = [
{ number: 1 },
{ number: 2 },
{ number: 3 }
];
function copy (obj) {
var newobj = obj.constructor === Array ? [] : {};
if(typeof obj !== 'object'){
return;
}
for(var i in obj){
newobj[i] = typeof obj[i] === 'object' ? copy(obj[i]) : obj[i];
}
return newobj
}
var copyArray = copy(array)
copyArray[0].number = 100;
console.log(array); // [{number: 1}, { number: 2 }, { number: 3 }]
console.log(copyArray); // [{number: 100}, { number: 2 }, { number: 3 }]
对象
1.利用循环和递归的方式
function deepClone(obj, newObj) {
var newObj = newObj || {};
for (let key in obj) {
if (typeof obj[key] == 'object') {
newObj[key] = (obj[key].constructor === Array) ? [] : {}
deepClone(obj[key], newObj[key]);
} else {
newObj[key] = obj[key]
}
}
return newObj;
}
注意:在循环递归中需要注意设置临界值(typeof obj[key] == ‘object’),否则会造成死循环。
循环递归可以处理对象中嵌套数组或对象的问题。相当于第二种方法的优化。
2.for in循环遍历对象
let obj1={count:1,name:'grace',age:1};
let obj2 = copyObj(obj){
let res = {};
for(let key in obj){
res[key]=obj[key];
}
return res;
}
3.Object.assign() 对象的合并
利用Object.assign(), 第一个参数必须是空对象
var obj = {name:'123',age:13};
var obj2 = Object.assign({},obj1);
缺点:只能深度拷贝对象的第一层,如果对象中的属性也是对象的话,没有办法进行深度拷贝的。
4.json暴力转化
通过JSON.stringify() 和 JSON.parse() 将对象转为字符串之后在转为对象。
var obj = { name: '123' }
var obj2 = JSON.parse(JSON.stringify(obj))
console.log(obj);
console.log(obj2);
这种简单粗暴的方式有局限性,当值为undefined、function、symbol会在转换过程中被忽略。
总结
以上就是今天的内容。