高新快速建设网站找哪家,网站建设运营公司推荐,凡科互动app,wordpress和discuz对比深浅拷贝
经典真题
深拷贝和浅拷贝的区别#xff1f;如何实现
深拷贝和浅拷贝概念
首先#xff0c;我们需要明确深拷贝和浅拷贝的概念。 浅拷贝#xff1a;只是拷贝了基本类型的数据#xff0c;而引用类型数据#xff0c;复制后也是会发生引用#xff0c;我们把这种拷…深浅拷贝
经典真题
深拷贝和浅拷贝的区别如何实现
深拷贝和浅拷贝概念
首先我们需要明确深拷贝和浅拷贝的概念。 浅拷贝只是拷贝了基本类型的数据而引用类型数据复制后也是会发生引用我们把这种拷贝叫做浅拷贝(浅复制)。浅拷贝只复制指向某个对象的指针引用地址而不复制对象本身新旧对象还是共享同一块内存。 深拷贝在堆中重新分配内存并且把源对象所有属性都进行新建拷贝以保证深拷贝的对象的引用图不包含任何原有对象或对象图上的任何对象拷贝后的对象与原来的对象是完全隔离互不影响。
浅拷贝方法
接下来我们来看一下对象有哪些浅拷贝方法。
1. 直接赋值
直接赋值是最常见的一种浅拷贝方式。例如
var stu {name: xiejie,age: 18
}
// 直接赋值
var stu2 stu;
stu2.name zhangsan;
console.log(stu); // { name: zhangsan, age: 18 }
console.log(stu2); // { name: zhangsan, age: 18 }2. Object.assign 方法
我们先来看一下 Object.assign 方法的基本用法。
该方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。
如下
var stu {name: xiejie
}
var stu2 Object.assign(stu, { age: 18 }, { gender: male })
console.log(stu2); // { name: xiejie, age: 18, gender: male }在上面的代码中我们有一个对象 stu然后使用 Object.assign 方法将后面两个对象的属性值分配到 stu 目标对象上面。
最终得到 { name: ‘xiejie’, age: 18, gender: ‘male’ } 这个对象。
通过这个方法我们就可以实现一个对象的拷贝。例如
const stu {name: xiejie,age: 18
}
const stu2 Object.assign({}, stu)
stu2.name zhangsan;
console.log(stu); // { name: xiejie, age: 18 }
console.log(stu2); // { name: zhangsan, age: 18 }在上面的代码中我们使用 Object.assign 方法来对 stu 方法进行拷贝并且可以看到修改拷贝后对象的值并没有影响原来的对象这仿佛实现了一个深拷贝。
然而Object.assign 方法事实上是一个浅拷贝。
当对象的属性值对应的是一个对象时该方法拷贝的是对象的属性的引用而不是对象本身。
例如
const stu {name: xiejie,age: 18,stuInfo: {No: 1,score: 100}
}
const stu2 Object.assign({}, stu)
stu2.name zhangsan;
stu2.stuInfo.score 90;
console.log(stu); // { name: xiejie, age: 18, stuInfo: { No: 1, score: 90 } }
console.log(stu2); // { name: zhangsan, age: 18, stuInfo: { No: 1, score: 90 } }3. ES6 扩展运算符
首先我们还是来回顾一下 ES6 扩展运算符的基本用法。
ES6 扩展运算符可以将数组表达式或者 string 在语法层面展开还可以在构造字面量对象时将对象表达式按 key-value 的方式展开。
例如
var arr [1, 2, 3];
var arr2 [3, 5, 8, 1, ...arr]; // 展开数组
console.log(arr2); // [3, 5, 8, 1, 1, 2, 3]var stu {name: xiejie,age: 18
}
var stu2 { ...stu, score: 100 }; // 展开对象
console.log(stu2); // { name: xiejie, age: 18, score: 100 }接下来我们来使用扩展运算符来实现对象的拷贝如下
const stu {name: xiejie,age: 18
}
const stu2 {...stu}
stu2.name zhangsan;
console.log(stu); // { name: xiejie, age: 18 }
console.log(stu2); // { name: zhangsan, age: 18 }但是和 Object.assign 方法一样如果对象中某个属性对应的值为引用类型那么直接拷贝的是引用地址。如下
const stu {name: xiejie,age: 18,stuInfo: {No: 1,score: 100}
}
const stu2 {...stu}
stu2.name zhangsan;
stu2.stuInfo.score 90;
console.log(stu); // { name: xiejie, age: 18, stuInfo: { No: 1, score: 90 } }
console.log(stu2); // { name: zhangsan, age: 18, stuInfo: { No: 1, score: 90 } }4. 数组的 slice 和 concat 方法
在 javascript 中数组也是一种对象所以也会涉及到深浅拷贝的问题。
在 Array 中的 slice 和 concat 方法不修改原数组只会返回一个浅复制了原数组中的元素的一个新数组。
例如
// concat 拷贝数组
var arr1 [1, true, Hello];
var arr2 arr1.concat();
console.log(arr1); // [ 1, true, Hello ]
console.log(arr2); // [ 1, true, Hello ]arr2[0] 2;
console.log(arr1); // [ 1, true, Hello ]
console.log(arr2); // [ 2, true, Hello ]// slice 拷贝数组
var arr1 [1, true, Hello];
var arr2 arr1.slice();
console.log(arr1); // [ 1, true, Hello ]
console.log(arr2); // [ 1, true, Hello ]arr2[0] 2;
console.log(arr1); // [ 1, true, Hello ]
console.log(arr2); // [ 2, true, Hello ]但是这两个方法仍然是浅拷贝。如果一旦涉及到数组里面的元素是引用类型那么这两个方法是直接拷贝的引用地址。如下
// concat 拷贝数组
var arr1 [1, true, Hello, { name: xiejie, age: 18 }];
var arr2 arr1.concat();
console.log(arr1); // [ 1, true, Hello, { name: xiejie, age: 18 } ]
console.log(arr2); // [ 1, true, Hello, { name: xiejie, age: 18 } ]arr2[0] 2;
arr2[3].age 19;
console.log(arr1); // [ 1, true, Hello, { name: xiejie, age: 19 } ]
console.log(arr2); // [ 2, true, Hello, { name: xiejie, age: 19 } ]// concat 拷贝数组
var arr1 [1, true, Hello, { name: xiejie, age: 18 }];
var arr2 arr1.slice();
console.log(arr1); // [ 1, true, Hello, { name: xiejie, age: 18 } ]
console.log(arr2); // [ 1, true, Hello, { name: xiejie, age: 18 } ]arr2[0] 2;
arr2[3].age 19;
console.log(arr1); // [ 1, true, Hello, { name: xiejie, age: 19 } ]
console.log(arr2); // [ 2, true, Hello, { name: xiejie, age: 19 } ]5. jQuery 中的 $.extend
在 jQuery 中$.extend(deep,target,object1,objectN) 方法可以进行深浅拷贝。各参数说明如下
deep如过设为 true 为深拷贝默认是 false 浅拷贝target要拷贝的目标对象object1待拷贝到第一个对象的对象objectN待拷贝到第N个对象的对象
来看一个具体的示例
bodyscript srchttps://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js/scriptscriptconst obj {name: wade,age: 37,friend: {name: james,age: 34}}const cloneObj {};// deep 默认为 false 为浅拷贝$.extend(cloneObj, obj);obj.friend.name rose;console.log(obj);console.log(cloneObj);/script
/body效果 深拷贝方法
说完了浅拷贝接下来我们来看如何实现深拷贝。
总结一下大致有如下的方式。
1. JSON.parse(JSON.stringify)
这是一个广为流传的深拷贝方式用 JSON.stringify 将对象转成 JSON 字符串再用 JSON.parse 方法把字符串解析成对象一去一来新的对象产生了而且对象会开辟新的栈实现深拷贝。
示例如下
const stu {name: xiejie,age: 18,stuInfo: {No: 1,score: 100}
}
const stu2 JSON.parse(JSON.stringify(stu));
stu2.name zhangsan;
stu2.stuInfo.score 90;
console.log(stu); // { name: xiejie, age: 18, stuInfo: { No: 1, score: 100 } }
console.log(stu2); // { name: zhangsan, age: 18, stuInfo: { No: 1, score: 90 } }这种方式看似能够解决问题但是这种方法也有一个缺点那就是不能处理函数。
这是因为 JSON.stringify 方法是将一个 javascript 值对象或者数组转换为一个 JSON 字符串而 JSON 字符串是不能够接受函数的。同样正则对象也一样在 JSON.parse 解析时会发生错误。
例如
const stu {name: xiejie,age: 18,stuInfo: {No: 1,score: 100,saySth: function () {console.log(我是一个学生);}}
}
const stu2 JSON.parse(JSON.stringify(stu));
stu2.name zhangsan;
stu2.stuInfo.score 90;
console.log(stu); // { name: xiejie, age: 18, stuInfo: { No: 1, score: 100, saySth: [Function: saySth] }}
console.log(stu2); // { name: zhangsan, age: 18, stuInfo: { No: 1, score: 90 } }可以看到在原对象中有方法拷贝之后新对象中没有方法了。
2. $.extend(deep,target,object1,objectN)
前面在介绍浅拷贝时提到了 jQuery 的这个方法该方法既能实现浅拷贝也能实现深拷贝。要实现深拷贝只需要将第一个参数设置为 true 即可。例如
bodyscript srchttps://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js/scriptscriptconst obj {name: wade,age: 37,friend: {name: james,age: 34}}const cloneObj {};// deep 设为 true 为深拷贝$.extend(true, cloneObj, obj);obj.friend.name rose;console.log(obj);console.log(cloneObj);/script
/body效果 3. 手写递归方法
最终还是只有靠我们自己手写递归方法来实现深拷贝。
示例如下
function deepClone(target) {var result;// 判断是否是对象类型if (typeof target object) {// 判断是否是数组类型if (Array.isArray(target)) {result []; // 如果是数组,创建一个空数组// 遍历数组的键for (var i in target) {// 递归调用result.push(deepClone(target[i]))}} else if (target null) {// 再判断是否是 null// 如果是直接等于 nullresult null;} else if (target.constructor RegExp) {// 判断是否是正则对象// 如果是,直接赋值拷贝result target;} else if (target.constructor Date) {// 判断是否是日期对象// 如果是,直接赋值拷贝result target;} else {// 则是对象// 创建一个空对象result {};// 遍历该对象的每一个键for (var i in target) {// 递归调用result[i] deepClone(target[i]);}}} else {// 表示不是对象类型则是简单数据类型 直接赋值result target;}// 返回结果return result;
}在上面的代码中我们封装了一个名为 deepClone 的方法在该方法中通过递归调用的形式来深度拷贝一个对象。
下面是 2 段测试代码
// 测试1
const stu {name: xiejie,age: 18,stuInfo: {No: 1,score: 100,saySth: function () {console.log(我是一个学生);}}
}
const stu2 deepClone(stu)
stu2.name zhangsan;
stu2.stuInfo.score 90;
console.log(stu); // { name: xiejie, age: 18, stuInfo: { No: 1, score: 100, saySth: [Function: saySth] }}
console.log(stu2); // { name: xiejie, age: 18, stuInfo: { No: 1, score: 90, saySth: [Function: saySth] }}// 测试2
var arr1 [1, true, Hello, { name: xiejie, age: 18 }];
var arr2 deepClone(arr1)
console.log(arr1); // [ 1, true, Hello, { name: xiejie, age: 18 } ]
console.log(arr2); // [ 1, true, Hello, { name: xiejie, age: 18 } ]arr2[0] 2;
arr2[3].age 19;
console.log(arr1); // [ 1, true, Hello, { name: xiejie, age: 18 } ]
console.log(arr2); // [ 2, true, Hello, { name: xiejie, age: 19 } ]真题解答
深拷贝和浅拷贝的区别如何实现 参考答案 浅拷贝只是拷贝了基本类型的数据而引用类型数据复制后也是会发生引用我们把这种拷贝叫做浅拷贝浅复制 浅拷贝只复制指向某个对象的指针而不复制对象本身新旧对象还是共享同一块内存。 深拷贝在堆中重新分配内存并且把源对象所有属性都进行新建拷贝以保证深拷贝的对象的引用图不包含任何原有对象或对象图上的任何对象拷贝后的对象与原来的对象是完全隔离互不影响。 浅拷贝方法 直接赋值Object.assign 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象然后返回目标对象。当拷贝的 object 只有一层的时候是深拷贝但是当拷贝的对象属性值又是一个引用时换句话说有多层时就是一个浅拷贝。ES6 扩展运算符当 object 只有一层的时候也是深拷贝。有多层时是浅拷贝。Array.prototype.concat 方法Array.prototype.slice 方法jQuery 中的 . e x t e n d ∗ 在 ∗ j Q u e r y ∗ 中 ∗ .extend*在 *jQuery* 中* .extend∗在∗jQuery∗中∗.extend(deep,target,object1,objectN) 方法可以进行深浅拷贝。deep 如过设为 true 为深拷贝默认是 false 浅拷贝。 深拷贝方法 $.extend(deep,target,object1,objectN)将 deep 设置为 trueJSON.parse(JSON.stringify)用 JSON.stringify 将对象转成 JSON 字符串再用 JSON.parse 方法把字符串解析成对象一去一来新的对象产生了而且对象会开辟新的栈实现深拷贝。这种方法虽然可以实现数组或对象深拷贝但不能处理函数。手写递归 示例代码如下 function deepCopy(oldObj, newobj) {for (var key in oldObj) {var item oldObj[key];// 判断是否是对象if (item instanceof Object) {if (item instanceof Function) {newobj[key] oldObj[key];} else {newobj[key] {}; //定义一个空的对象来接收拷贝的内容deepCopy(item, newobj[key]); //递归调用}// 判断是否是数组} else if (item instanceof Array) {newobj[key] []; //定义一个空的数组来接收拷贝的内容deepCopy(item, newobj[key]); //递归调用} else {newobj[key] oldObj[key];}}
}-EOF-