深拷贝和浅拷贝
数据类型分为:基本数据类型和引用类型
首先基本数据类型分为:number,string,boolean,null,undefined,symbol以及未来ES10新增的BigInt(任意精度整数)七类。
引用类型分为Array,Object,Function,正则等。
两种数据类型怎么进行存储数据的
基本数据类型
对应基本数据类型来说,名和值都是存储在栈内存中。例如let a = 1,那么名a和值b都是存储在栈内存中,如果b=a,将a复制给b时,栈内存会新开辟一个内存,这样a与b互不影响,当a的值发生改变时,不会影响到b。基本数据类型不存在深拷贝还是浅拷贝这一说法,此说法只存在于引用型数据。
引用类型
引用数据类型,名是存储在栈内存中,值是存储在堆内存里面,但是栈内存会提供一个引用的地址指向堆内存中的值。当b=a,将a复制给b时,其实复制的是a的引用地址,而并不是堆里面的值。当改变a的值的时候,由于a和b指向的是同一个地址,那么b自然会受到影响,这就是浅拷贝。那么要是在堆内存中也开辟一个新的内存专门为b存放值,那么就能达到深拷贝的效果了。
怎么实现深拷贝的
1、通过递归方式实现深拷贝
遍历对象、数组,直到里边都是基本数据类型,然后再去复制,就是深度拷贝。
function deepClone(obj) {
var target = {};
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
if (typeof obj[key] === 'object') {
target[key] = deepClone(obj[key]);
} else {
target[key] = obj[key];
}
}
}
return target;
}
2、JSON.parse(JSON.stringify(obj))
用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。只能实现数组或对象深拷贝,但不能处理函数。
let obj = {
id: 1,
name: '张三',
age: 10,
}
let newObj = JSON.parse(JSON.stringify(obj))
3、jQuery的extend方法实现深拷贝
var array = [1,2,3,4];
var newArray = $.extend(true,[],array); // true为深拷贝,false为浅拷贝
怎么实现浅拷贝
1、Object.assign()
Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
Object.assign(target, ...sources)
arget--->目标对象
source--->源对象
返回值:target,即目标对象
只有一级属性为深拷贝,二级属性后就是浅拷贝
浅拷贝:
//如果只是想将两个或多个对象的属性合并到一起,不改变原有对象的属性,可以用一个空的对象作为target对象。
var target={name:'guxin',age:25};
var source={state:'single'}
var result=Object.assign({},target,source);
console.log(result)//{name: 'guxin', age: 25, state: 'single'}
深拷贝:
var obj = { a: {a: "kobe", b: 39} };
var initalObj = Object.assign({}, obj);
initalObj.a.a = "wade";
console.log(obj.a.a);
source上的state属性可以合并到target对象上(如果有同名属性的话,后面的属性值会覆盖前面的属性值):
var target={name:'guxin',age:25};
var source={state:'single'}
var result=Object.assign(target,source);
console.log(target,target==result);//{name: 'guxin', age: 25, state: 'single'} true
2、扩展运算符
只有一级属性为深拷贝,二级属性后就是浅拷贝
深拷贝:
var obj = {a: 1,b: 2}
var obj1 = {…obj} //深拷贝
3、数组使用数组方法(concat、slice)
只有一级属性为深拷贝,二级属性后就是浅拷贝
深拷贝:
var arr1 = [1, 2, 3, 4]
var arr2 = arr1.concat()
var arr3 = arr1.slice(1)
浅拷贝:
let arr = [1, 3, {username: 'kobe' }];
let arr2=arr.concat();
arr2[2].username = 'wade';
console.log(arr);
let arr = [1, 3, {username: 'kobe' }];
let arr3 = arr.slice();
arr3[2].username = 'wade'
console.log(arr);
Array的slice和concat方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。如:
let arr = [1, 3, { username: ' kobe' }];
let arr3 = arr.slice();
arr3[1] = 2
console.log(arr,arr3);