概述
1. 相关知识点
1.1 基本类型与引用类型分类
基本类型:number,string,boolean,null,undefined,symbol及BigInt(任意精度整数)七类;
引用类型:对象、数组、函数等;
1.2 JS中变量的存储方式
栈:自动分配内存空间,系统自动释放,里面存放的是基本类型的名值和引用类型的名(地址);
堆:动态分配的内存,大小不定,也不会自动释放,里面存放引用类型的值;
1.2.1 基本类型
let a = 1;
当你b = a复制时,栈内存会新开辟一个内存
当你此时修改a=2,对b并不会造成影响;
let a=1,b=a;
虽然b不受a影响,但这也算不上深拷贝。因为深拷贝本身只针对较为复杂的object类型数据。
1.2.2 引用数据类型
let a = [0,1,2,3,4];
当 b = a 进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值;
当a[0] = 1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,
这就是浅拷贝。
要是在堆内存中也开辟一个新的内存专门为b存放值(就像基本类型那样),就达到深拷贝的效果了。
2. 实现浅拷贝的方法
2.1 for···in 只循环第一层
// 只复制第一层的浅拷贝
function simpleCopy(obj1) {
var obj2 = Array.isArray(obj1) ? [] : {};
for (let i in obj1) {
obj2[i] = obj1[i];
}
return obj2;
}
var obj1 = {
a: 1,
b: 2,
c: {
c1: 3
}
}
var obj2 = simpleCopy(obj1);
obj2.a = 3;
obj2.c.c1 = 4;
console.log(obj1.a,obj2.a); // 1 3
console.log(obj1.c.c1,obj2.c.c1); // 4 4
2.2 Object.assign方法
var obj1 = {
a: 1,
b: 2,
c: {
c1: 3
}
}
var obj2 = Object.assign({},obj1);
obj2.a = 3;
obj2.c.c1 = 4
console.log(obj1.a,obj2.a) // 1 3
console.log(obj1.c.c1,obj2.c.c1); // 4 4
2.3 直接用 = 赋值
let a = [0,1,2,3,4],
b = a;
console.log(a===b); // true
a[0]=1;
console.log(a,b); // [1,1,2,3,4] [1,1,2,3,4]
3. 实现深拷贝的方法
3.1 采用递归去拷贝所有层级属性
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj === "object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
// 判断ojb子元素是否为对象,如果是,递归复制
if(obj[key] && typeof obj[key] === "object"){
objClone[key] = deepClone(obj[key]);
}else{
// 如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let a = [1,2,3,4]
let b = deepClone(a);
a[0]=2;
console.log(a,b); // [2,2,3,4] [1,2,3,4]
let obj1 = {
a: 1,
b: 2,
c: {
c1: 3
}
}
let obj2 = deepClone(obj1)
obj2.c.c1 = 4
console.log(obj1,obj2); // {a:1,b:2,c:{c1:3}} {a:1,b:2,c:{c1:4}}
3.2 通过JSON对象来实现深拷贝
注意: 无法实现对象中方法的深拷贝
function deepClone(obj) {
var _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj);
return objClone;
}
let a = [1,2,3,4]
let b = deepClone(a);
a[0]=2;
console.log(a,b); // [2,2,3,4] [1,2,3,4]
let obj1 = {
a: 1,
b: 2,
c: {
c1: 3,
c2:function(){ // 无法实现对对象中方法的深拷贝
console.log('深拷贝')
}
}
}
let obj2 = deepClone(obj1)
obj2.c.c1 = 4
console.log(obj1,obj2); // {a:1,b:2,c:{c1:3,c2:f()}} {a:1,b:2,c:{c1:4}}
3.3 通过 jQuery 中的 extend 方法实现深拷贝
$.extend( [deep ], target, object1 [, objectN ] )
deep表示是否深拷贝,true为深拷贝,false为浅拷贝
target Object类型 目标对象,其他对象的成员属性将被附加到该对象上;
object1 objectN(可选), Object类型 第一个以及第N个被合并的对象;
var array1 = [1,2,3,4];
var newArray = $.extend(true,[],array1); // true为深拷贝,false为浅拷贝
3.4 lodash函数库 实现深拷贝
lodash中文网
let result = _.cloneDeep(test)
3.5 Reflect法
reflect简介
function isObject(val) {
return val != null && typeof val === 'object' && Array.isArray(val) === false;
}
function deepClone(obj) {
let isArray = Array.isArray(obj)
let cloneObj = isArray ? [...obj] : { ...obj }
Reflect.ownKeys(cloneObj).forEach(key => {
cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
})
return cloneObj
}
let a = [1,2,3,4]
let b = deepClone(a);
a[0]=2;
console.log(a,b); // [2,2,3,4] [1,2,3,4]
let obj1 = {
a: 1,
b: 2,
c: {
c1: 3,
c2:function(){
console.log('深拷贝')
}
}
}
let obj2 = deepClone(obj1)
obj2.c.c1 = 4
console.log(obj1,obj2); // {a:1,b:2,c:{c1:3,c2:f}} {a:1,b:2,c:{c1:4,c2:f}}
3.6 手动实现深拷贝
let obj1 = {
a: 1,
b: 2
}
let obj2 = {
a: obj1.a,
b: obj1.b
}
obj2.a = 3;
alert(obj1.a); // 1
alert(obj2.a); // 3
3.7 Object.assign 方法
注意:
如果对象的 value 是基本类型,可用 Object.assign 来实现深拷贝
// 对象的 value 是基本类型
var obj = {
a: 1,
b: 2,
}
var obj1 = Object.assign({}, obj); // obj赋值给一个空{}
obj1.a = 3;
console.log(obj.a) // 1
3.8 slice 实现对数组的深拷贝
注意:
当数组里面的值是基本数据类型,比如String,Number,Boolean时,属于深拷贝;
当数组里面的值是引用数据类型,比如Object,Array时,属于浅拷贝;
// 当数组里面的值是基本数据类型,比如 String,Number,Boolean 时,属于深拷贝
// 当数组里面的值是引用数据类型,比如 Object,Array 时,属于浅拷贝
var arr1 = ["1","2","3"];
var arr2 = arr1.slice(0);
arr2[1] = "9";
console.log(arr1); // ["1","2","3"]
console.log(arr2); // ["1","9","3"]
3.9 concat 实现对数组的深拷贝
注意:
当数组里面的值是基本数据类型,比如 String,Number,Boolean 时,属于深拷贝;
当数组里面的值是引用数据类型,比如 Object,Array 时,属于浅拷贝;
// 当数组里面的值是基本数据类型,比如String,Number,Boolean时,属于深拷贝;
// 当数组里面的值是引用数据类型,比如Object,Array时,属于浅拷贝;
var arr1 = ["1","2","3"];
var arr2 = arr1.concat();
arr2[1] = "9";
console.log(arr1); // ["1","2","3"]
console.log(arr2); // ["1","9","3"]
var arr1 = [{a:1},{b:2},{c:3}];
var arr2 = arr1.concat();
arr2[0].a = "9";
console.log(arr1[0].a); // 9
console.log(arr2[0].a); // 9
3.10 通过 var newObj = Object.create(oldObj)
**注意:**无法实现对对象中方法的深拷贝;
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i]; // 避免相互引用对象导致死循环,如 initalObj.a = initalObj 的情况
if(prop === obj) {
continue;
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
} else {
obj[i] = prop;
}
}
return obj;
}
let obj1 = {
a: 1,
b: 2,
c: {
c1: 3,
c2:function(){
console.log('深拷贝')
}
}
}
let obj2 = deepClone(obj1)
obj2.c.c1 = 4
console.log(obj1,obj2); // {a:1,b:2,c:{c1:3,c2:f}} {a:1,b:2,c:{c1:4}}
3.11 使用 扩展运算符 实现深拷贝
注意:
当value是基本数据类型,比如 String,Number,Boolean 时,属于深拷贝;
当value是引用类型的值,比如 Object,Array,属于浅拷贝;
let obj1 = {
a: 1,
b: 2,
c: {
c1: 3,
c2:function(){
console.log('深拷贝')
}
}
}
let obj2 = {...obj1} // 此时拷贝了 {c1:3} 的引用地址
obj2.c.c1 = 4 // 改变对象里面的值
console.log(obj1,obj2); // {a:1,b:2,c:{c1:4,c2:f}} {a:1,b:2,c:{c1:4,c2:f}}
let obj3 = {...obj1}
obj3.c = {c1:5} // 改变引用的对象,实际改变了引用对象的地址
console.log(obj1,obj3); // {a:1,b:2,c:{c1:4,c2:f}} {a:1,b:2,c:{c1:5}}
最后
以上就是俏皮天空为你收集整理的浅拷贝和深拷贝的相关知识点和实现方式的全部内容,希望文章能够帮你解决浅拷贝和深拷贝的相关知识点和实现方式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复