栈stack & 堆heap
一般数据类型的数据存储————栈(存放的是基本类型的值和引用类型的地址)
引用类型的数据存储 ————堆(里面存放引用类型的值)
-
浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。
- 如果属性是基本类型,拷贝的就是基本类型的值
- 如果属性是引用类型,拷贝的就是内存地址,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
-
深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
赋值和深浅拷贝的区别
- 当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此**,两个对象是联动的**。
- 浅拷贝:重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享同一块内存,会相互影响。
引用类型你动,原来的也跟着动。
- 深拷贝:从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。
图源:https://www.bilibili.com/video/BV1sN411974w?p=5
浅拷贝实现方式
浅拷贝只会对对象的各个属性进行复制,导致引用类型指向同一块内存地址。
实现方式:
- Object.assign()
- lodash 里面的 _.clone
- …展开运算符
- Array.prototype.concat
- Array.prototype.slice
// 浅拷贝的函数封装
function shallowCopy(obj) {
var dst = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
dst[prop] = obj[prop];
}
}
return dst;
}
Object.assign():
var obj = { a: {a: "kobe", b: 39} };
var initalObj = Object.assign({}, obj);
initalObj.a.a = "wade";
console.log(obj.a.a); // wade
Array.prototype.concat()
let arr = [1, 3, {
username: 'kobe'
}];
let arr2=arr.concat();
arr2[2].username = 'wade';
console.log(arr);
Array.prototype.slice()
let arr = [1, 3, {
username: ' kobe'
}];
let arr3 = arr.slice();
arr3[2].username = 'wade'
console.log(arr);
Array的slice和concat方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。
深拷贝实现方式
实现方式:
- JSON.parse(JSON.stringify())
- 手写递归
- cloneDeep
- Jquery.extend()
1. JSON.parse(JSON.stringify())
原理: 用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
但不能处理函数
let arr = [1, 3, {
username: ' kobe'
}];
let arr4 = JSON.parse(JSON.stringify(arr));
arr4[2].username = 'duncan';
console.log(arr, arr4)
2. 手写递归方法
function deepClone(obj) {
var cloneObj = new obj.constructor();
if (obj === null) return obj;
// a instanceof b: b的prototype是否在a的原型链上
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
if (typeof obj !== 'object') return obj;
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
cloneObj[prop] = deepClone(obj[prop]);
}
}
return cloneObj;
}
3. 函数库lodash
var _ = require('lodash');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);
// false
参考:https://github.com/ljianshu/Blog/issues/5