深拷贝和浅拷贝
堆和栈的区别
栈: (stack) 自动分配的空间,由系统自动释放
堆: (heap) 动态分配内存,大小不定, 也不会自动释放
数据类型
基本数据类型主要是:undefined
,boolean
,number
,string
,null
、symbol
。
引用数据类型 对象,数组,function
let a = 1;
let b = a;
b = 15;
console.log(a, b) //1 15
赋值过程如下
栈里面开辟一块内存,放1,之后将a 与1关联起来
再开辟一块内存,放15 ,把之前的关联取消,在和b关联起来重新赋值 原来的值保持不变
引用类型数据是存放在堆中,当obj1
赋值给obj2
执行过程如下图,
let obj1 = {a:1}
let obj2 = obj1;
obj2.a = 100;
console.log(obj1.a)//100
传值和传址
传值和传地址如下图
传值: 就是给变量赋常量值
传址: 在堆内里取一块区域,放对象值然后有个地址, 栈里有个变量,把一个地址赋值给变量。
深浅拷贝
原始数据,是没有深浅拷贝的区别
引用类型数据才有深浅拷贝
使用场景: 复杂对象
浅拷贝
赋值对象 所有的属性 都不是 引用类型的时候,我们可以使用浅拷贝。
遍历并复制,最后返回一个对象。
浅拷贝:只复制一层对象,当对象的属性是引用类型时,实际复制的是其引用。
引用值指向发生改变时候,也会跟着改变。
使用for in
// 实现浅拷贝
let shallowCopy = obj => {
let rst = {};
// 遍历对象
for (let key in obj) {
// 只复制本身拥有的属性(非继承过来的属性)枚举属性
if (obj.hasOwnProperty(key)) {
rst[key] = obj[key];
}
}
return rst;
}
let person = {
name: '张三',
age: 12,
eat: function(){},
car:['自行车', '奔驰'],
chlid:[{
name: '李四',
age:2
},{
name:'王五',
age: 30
}]
}
let newPerson = shallowCopy(person);
newPerson.name = '罗志祥';
newPerson.age = 50;
newPerson.chlid[0].name = '柴扉'
newPerson.car[1] = '破烂车'
console.log(newPerson, person);
使用扩展运算符
let star = { name: '刘亦菲' };
let newStar = { ...star };
newStar.name = '迪丽热巴';
console.log(star.name);
let girl = {
name: '死胖子', // 赋值
info: {
height: 180,
weight: 180
}
}
let newGirl = { ...girl };
newGirl.info.height = 140;
console.log(girl.info.height); //
扩展运算符它的value是原始数据类型的时候。是深拷贝。
当value是引用类型的时候,是浅拷贝
Object.assign
// Object.assign 可以把 n 个源对象拷贝到目标对象中去
/*
es6中的方法
Object.assign是深拷贝还是浅拷贝
*/
let person = {
name: '开心',
info: {
gender: '女',
hobby: '吃饭睡觉打豆豆'
}
}
// 第一级属性是深拷贝,以后级别浅拷贝
let lincancan = Object.assign({}, person);
console.log(lincancan);
lincancan.name = '林灿灿';
console.log(person.name); // 开心
lincancan.info.hobby = '吃鸡脚';
console.log(person.info.hobby); // 鸡脚
深拷贝
JSON.stringify
let obj = {
name: '小明',
dog: ['小花', '旺财']
}
let obj1 = JSON.parse(JSON.stringify(obj));
obj1.name = '小华';
obj1.dog[0] = '小白';
// console.log(obj1,obj)
let richGirl = [{
name:'开心',
car:['宝马','奔驰','保时捷'],
deive:function (){},
age:undefined
}]
let richBoy = JSON.parse(JSON.stringify(richGirl));
console.log(richBoy);
// 纯的JSON数据,不包含循环引用
递归实现
// 递归实现深拷贝
let deepClone = obj => {
let newObj = Array.isArray(obj) ? [] : {};
if (obj && typeof obj === 'object') {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === 'object') {
newObj[key] = deepClone(obj[key]);
} else {
// 如果不是对象直接拷贝
newObj[key] = obj[key];
}
}
}
}
return newObj;
}
let richGirl = {
name: '开心',
car: ['宝马', '奔驰', '保时捷'],
deive: function () { },
age: undefined
}
let richBoy = deepClone(richGirl);
// console.log(richBoy);
richBoy.deive = '渣男开大G';
richBoy.name = '小明';
richBoy.car = ['哈罗单车', '膜拜'];
richBoy.age = 20;
console.log(richGirl);
console.log(richBoy);
深拷贝:将 B 对象拷贝到 A 对象中,包括 B 里面的子对象.
浅拷贝:将 B 对象拷贝到 A 对象中,但不包括 B 里面的子对象
-- | 和原数据是否指向同一对象 | 第一层数据为基本数据类型 | 原数据中包含子对象 |
---|---|---|---|
赋值 | 是 | 改变会使原数据一同改变 | 改变会使原数据一同改变 |
浅拷贝 | 否 | 改变不会使原数据一同改变 | 改变会使原数据一同改变 |
深拷贝 | 否 | 改变不会使原数据一同改变 | 改变不会使原数据一同改变 |
/**
* 深拷贝
*
* 缺陷: 比如拷贝Symbol、拷贝函数、循环引用
*/
export const deepCopyJson = source => {
return JSON.parse(JSON.stringify(source));
};
/**
* 请试着实现一个可以解决 deepCopyJson 中不能拷贝的Symbol、循环引用问题的拷贝函数,
* 并且保证copy.test.js中的单元测试顺利通过。
*/
export const deepCopy = source => {};
- END -