深拷贝、浅拷贝
一.深、浅拷贝定义:
浅拷贝:即对象的浅拷贝会对“主”对象进行拷贝,但不会复制主对象里面的对象。”里面的对象“会在原来的对象和它的副本之间共享。
深拷贝:定义:深拷贝不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上,所以 对一个对象的修改并不会影响另一个对象。
二.深拷贝:
数组(注意:该数组只是单纯的数组,如果数组里面嵌套对象,则下面的几种方法都不是深拷贝。)
法一:for循环
var arr1 = [1,2,3];
var arr2 = copyArr(arr1);
function copyArr(arr){
var res=[];
for(var i=0,length=arr.length;i<length;i++)
{
res.push(arr[i]);
}
return res;
}
法二: slice()截取数组
var arr1 = [1,2,3];
var arr2 = arr1.slice(0);
法三: concat(),连接数组
var arr1 = [1,2,3];
var arr2 = arr1.concat();
对象:
法一:for循环
let obj1={count:1,name:'grace',age:1};
let obj2 = copyObj(obj){
let res = {};
for(let key in obj){
res[key]=obj[key]; }
return res;
}
法四:es6解构
var ary2 = [...ary1];
var [...ary2] = ary1;
法五:JSON解析
var ary2 = JSON.parse(JSON.stringify(ary1))
三、拷贝继承
利用对象的深拷贝方式即可,可以继承父类中构造函数和原型中的所有的属性和方法。
法一:for in方法
for (x in p1) {
// 对象的属性
// console.log(x);
// 对象的属性值
console.log(p1[x]);
// 只需要拷贝属性值即可
stu1[x] = p1[x];
}
法二、递归调用
// 递归调用
const deepCopy = (obj) => {
// 判断传入的值是否为一个对象
if (obj === null && typeof obj !== "object") {
return obj;
}
// 判断对象的类型 注意这里不考虑包装类对象
if (Object.prototype.toString.call(obj) === "[object Date]") {
return new Date(obj);
}
if (Object.prototype.toString.call(obj) === "[object RegExp]") {
return new RegExp(obj);
}
if (Object.prototype.toString.call(obj) === "[object Undefined]") {
return new Error(obj);
}
// 判断对象是类
let newObj = Array.isArray(obj) ? [] : {}
for(let item in obj){
if(typeof obj[item] === 'object') {
newObj[item] = deepCopy(obj[item])
}else {
newObj[item] = obj[item]
}
}
return newObj
};
const foo = {
name: '张三',
info: {
age: 24
}
}
const newFoo = deepCopy(foo)
console.log(foo, newFoo)
foo.info.age = 25
console.log(foo, newFoo)
法三、JSON.stringify + JSON.parse
:::info
更多关于JSON.stringigy的注意事项请看MDN
:::
// JSON.stringify
// 情况一: 对象内不存在undefined、symbol、function类型的属性时
// const foo = {
// name: '张三',
// info: {
// age: 24
// }
// }
// const newFoo = JSON.parse(JSON.stringify(foo))
// console.log(foo, newFoo) // { name: '张三', info: { age: 24 } } { name: '张三', info: { age: 24 } }
// foo.info.age = 25
// console.log(foo, newFoo) // { name: '张三', info: { age: 25 } } { name: '张三', info: { age: 24 } }
// 情况二:当对象内存在undefined、symbol、function类型的属性时,在序列化过程中会被忽略。
// 当属性为NaN 和 Infinity 格式的数值及 null 都会被当做 nul
// const foo = {
// name: "张三",
// age: undefined,
// height: 183,
// gender: Symbol("男"), //
// say: () => {},
// aa: NaN,
// };
// const newFoo = JSON.parse(JSON.stringify(foo));
// console.log(foo, newFoo); // {aa: NaN, age: undefined, gender: Symbol(男), height: 183, name: "张三"} { {name: '张三', height: 183, aa: null} }
// JSON.stringify() 第二个参数为可选参数,可以是一个函数或者数组,
// 当是数组时表示需要被转化的属性列表,但undeinfed,symbol,function类型的属性依然会被忽略
// const newFoo = JSON.parse(JSON.stringify(foo, ['name', 'age', 'gender', 'say', 'aa']));
// console.log(newFoo) // {name: '张三', aa: null}
法四、lodash
const _ = require('lodash')
const foo = {
name: '张三',
info: {
age: 24
}
}
const newFoo = _.cloneDeep(foo);
foo.info.age = 25
console.log(foo, newFoo) // { name: '张三', info: { age: 25 } } { name: '张三', info: { age: 24 } }
法五、Object.assgin
注意:只有当对象中没有嵌套对象时,才可以实现深拷贝
const foo = {
name: '张三',
age: 24
}
const newFoo = Object.assign({}, foo)
foo.age = 25
console.log(foo, newFoo) // {name: '张三', age: 25} {name: '张三', age: 24}
// 对象中有内嵌的对象时
const foo = {
name: '张三',
info: {
age: 24
}
}
const newFoo = Object.assign({}, foo)
foo.info.age = 25
console.log(foo, newFoo) // { name: '张三', info: { age: 25 } } { name: '张三', info: { age: 25 } }