浅拷贝
浅拷贝和赋值
- 基本数据类型可以直接赋值
- 引用数据类型直接赋值,那是指向同一个引用地址,所以用浅拷贝
浅拷贝只复制一层对象的属性,并不包括对象里面的为引用类型的数据
如何实现浅拷贝
对象
function shallowCopy(src) {
var dst = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop];
}
}
return dst;
}
[注释]:hasOwnProperty() 方法会返回一个布尔值,这个方法可以用来检测一个对象是否含有特定的自身(非继承)属性。
for…in 循环只会遍历可枚举属性,再加上 hasOwnProperty()方法,可以忽略掉继承属性,这样就能确保遍历的是Obj的可枚举的自身属性
数组
slice()和concat()
xxx.slice() 从头截取到尾
xxx.concat() 拼接
深拷贝
json实现
说白了 就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象
JSON.parse(JSON.stringify(obj))
//缺点:对象必须遵从JSON的格式
let obj1 = {
a: '1',
b: '2',
c: function func() {}
}
let obj4 = JSON.parse(JSON.stringify(obj1))
console.log(obj4) //{ a: '1', b: '2' } 好像漏了些什么
问题
- 如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象
- 如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象;
- 如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失
- 如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null
- 还有一点不好的地方是它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。同时如果对象中存在循环引用的情况也无法正确处理
Object.assign
Object.assign(target, …sources)
Object.assign() 方法用于将所有可枚举的属性的值从一个或多个源对象复制到目标对象。它将返回目标对象
// 复制
let c = Object.assign({}, { a: 'apple' });
console.log(c); // { a: 'apple' }
//合并
let o = {}
let c = Object.assign(o, { a: 'apple' }, { b: 'banana' }, { c: 'cake' } )
console.log(c) // { a: 'apple', b: 'banana', c: 'cake' }
//如果对象本身存在的属性会更新,不存在的属性会增加
let o = {
name:'pan'
}
let oo = {
name:'rui',
id:100
}
let c = Object.assign(o, oo);
console.log(o); //{name:'rui',id:100}
console.log(oo);//{name:'rui',id:100}
console.log(c);//{name:'rui',id:100}
迭代递归法
function judgeType (a) {
return Object.prototype.toString.call(a)
}
function deepCopy (a) {
var type = judgeType(a)
var data
if (type === '[object Array]') {
data = []
for (let i = 0; i < a.length; i++) {
data.push(deepCopy(a[i]))
}
} else if (type === '[object Object]') {
data = {}
for (const prop in a) {
if (a.hasOwnProperty(prop)) { // 非继承属性
data[prop] = deepCopy(a[prop])
}
}
} else {
data = a
}
return data
}