前言
自己迷茫了一段时间,技术很low,想想现在勉强算年轻,必须要努力一番。所以记录下这个过程。只是一个记录自己学习的过程。
感谢掘金上的各位大神,跟着你们一路混分。
浅拷贝
- 浅拷贝的属性如果是基本数据类型,拷贝的是这个基本数据类型的值;如果属性的引用类型,拷贝的是内存地址,所以如果一个对象改变了这个地址,就会影响到另外一个对象。
1.Object.asign
- Object.assign()把所有可枚举类型从一个或者多个对象复制到目标对象,返回目标对象。缺点:Object.assign的拷贝属性市有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性。
const obj1={a:1,b:2 }
const obj2={a:1,b:[2,3,4,5],c:2};
Object.assign(obj1,obj2);
console.log(obj1); //obj1={ a: 1, b: [ 2, 3, 4, 5 ], c: 2 }
-
Object.assign的使用场景
- 便捷的为一个类添加属性和方法
- 克隆对象,合并对象
- 为属性指定默认值(此处注意默认对象的属性值最好都是简单类型,不然会发生一些很错误覆盖的问题)
//Object.assign的使用场景
class Person {
constructor(x, y) {
Object.assign(this, {x, y});
}
}
Object.assign(Point.prototype, {
eatFood() {
console.log('hahah');
},
drinkWater() {
//···
}
});
//为属性指定默认值
const default={url:"http://xxxx.com",port:8888}
Object.assgin(obj1,default,obj2)
-
使用Object.assign()的坑
- 如果两个对象有相同的属性,则会覆盖。
- 不是对象会先转成对象。null和undefined在首参数上就会报错。
- 被拷贝的属性的更改会影响到拷贝之后的内容
//使用Object.assign需要注意的几个点:
const obj1={a:1,b:2 }
const obj2={a:1,b:[2,3,4,5],c:2};
Object.assign(obj1,obj2);
console.log(obj1); //obj1={ a: 1, b: [ 2, 3, 4, 5 ], c: 2 }
//2.不是对象会先转成对象。
Object.assign({},1);
Object.assign(undefined) // 报错
Object.assign(null) // 报错
let obj = {a: 1};
Object.assign(obj, undefined) === obj // true
Object.assign(obj, null) === obj // true
//3.被拷贝的属性的更改会影响到拷贝之后的内容(浅拷贝)
let obj1={a:{b:2}};
obj2={};
Object.assign(obj2,obj1)
obj1.a.b=3;
console.log(obj2.a.b) //3
...obj展开运算符
- 展开运算符是 ES6 中新提出来的一种运算符。在拷贝数组、对象以及拼接数组等方面都可以使用。
/**
* @name ...obj拷贝对象
*/
const obj1 = {
name: 'Mrking',
arr1: ['1', '2', '3'],
obj: {
name: 'fighter',
arr2: {b:{c:[1,2,3]}},
},
};
const obj2 = {...obj1};
console.log(obj1);
// {
// name: 'Mrking',
// arr1: [ '1', '2', '3' ],
// obj: { name: 'fighter', arr2: { b: [Object] } }
// }
console.log(obj2);
// {
// name: 'Mrking',
// arr1: [ '1', '2', '3' ],
// obj: { name: 'fighter', arr2: { b: [Object] } }
// }
手写一个浅拷贝
const shallowClone = (arr) => {
const cloneArray = [];
for (let prop in arr) {
if (arr.hasOwnProperty(prop)) {
cloneArray[prop] = arr[prop];
}
}
return dst;
}
const arr2 = shallowClone(arr1);
- 若是修改引用类型的值,还是会改变拷贝后的对象。修改基本数据类型,则没有影响。
深拷贝
- 深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存,当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相较于浅拷贝速度慢并且花销更大。深拷贝的两个对象互不影响。
JSON.parse(JSON.stringify(obj))
//深拷贝对象或者是数组
var a = {
type: 'dog',
desc: {
name: 'wangwang',
price: [300,500,1000]
}
};
var b = JSON.parse(JSON.stringify(a));
b.type = 'cat';
b.desc.price[2] = 600;
console.log(a); // { type: 'dog', desc: { name: 'wangwang', price: [ 300, 500, 1000 ] } }
console.log(b); // { type: 'dog', desc: { name: 'wangwang', price: [ 300, 500, 600 ] } }
局限性
说到JSON.parse(JSON.stringify(obj)),咱们直接上一段代码即可。
var a = {
type: 'dog',
desc: {
name: 'wangwang',
price: [300,500,1000]
},
sound:function(){
console.log('wangwangwang')
},
banType:{
a:undefined,
b:new Date(),
c:/[a-z]/,
d:NaN,
}
};
var b = JSON.parse(JSON.stringify(a));
console.log(a);
// {
// type: 'dog',
// desc: { name: 'wangwang', price: [ 300, 500, 1000 ] },
// sound: [Function: sound],
// banType: { a: undefined, b: 2020-05-03T03:20:21.019Z, c: /[a-z]/, d: NaN }
// }
console.log(b);
// {
// type: 'dog',
// desc: { name: 'wangwang', price: [ 300, 500, 1000 ] },
// banType: { b: '2020-05-03T03:20:21.019Z', c: {}, d: null }
// }
归纳:
- 不能存放函数或者 Undefined,否则会丢失函数或者 Undefined。
- 不要存放时间对象,否则会变成字符串形式。
- 不能存放 RegExp对象,否则会变成空对象。
- 不能存放NaN,会变成null。
手写一个简单版本深拷贝
- 深拷贝的重点也就是在于如何把引用类型拷贝过来。
function simpleDeepClone(a) {
const b=Array.isArray(a) ? [] : {}
for (const key of Object.keys(a)) {
const type = typeof a[key]
if (type !== 'object' || a[key] === null) {
b[key] = a[key]
} else {
b[key] = simpleDeepClone(a[key])
}
}
return b
}
最后
私下需要完善的地方:
- 完善深拷贝的手写方法
- 了解lodash函数库的cloneDeep()方法
- 框架jQuery的extend()方法