代码
可以实现数组或对象深拷贝,但不能处理函数,undefined
function depClone(obj) {
var result = JSON.parse(JSON.stringify(obj));
return result;
}
var obj = {
family: {
border: "wangzhipeng",
father: "wanglicai",
mother: "sunaiyun"
},
name: "gino",
sex: "male",
age: "27"
};
var obj1 = depClone(obj)
obj1.family.border = 'aa'
console.log(obj) // 原对象没有改变
console.log(obj1) //新对象有改变
效果
深浅拷贝
判断对象是否有此属性
in与hasOwnProperty
所有继承了 Object 的对象都会继承到 hasOwnProperty 方法。这个方法可以用来检测一个对象是否含有特定的自身属性;和 in 运算符不同,该方法会忽略掉那些从原型链上继承到的属性
function Test (name) {
this.name = name
this.log = function () {
console.log('this.name', this.name)
}
}
Test.prototype.sex = 22
const t = new Test()
t.age = 11
for (let key in t) {
console.log('key', key) //name,log,sex,age
if (t.hasOwnProperty(key)) {
console.log('key', key) //name,log,age
}
}
JSON
- 缺点
- 会忽略掉对象中属性值为undefined和函数的属性 由于方法的底层
- 实现用了递归,如果对象存在循环引用,会爆栈(报循环引用的错)
递归
- 优点
- 可以解决JSON方式忽略属性值为undefined和function的属性的问题
- 对象存在循环引用时仍然会爆栈
function deepCopy (obj) {
const target = {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// key为对象自身可枚举的属性
if (
Object.prototype.toString.call(obj[key]) === '[object Object]'
) {
// 属性值为对象,递归调用
target[key] = deepCopy(obj[key])
} else {
target[key] = obj[key]
}
}
}
return target
}
闭包 + 递归
解决了JSON方式和递归方式存在的问题,可实现真正的深拷贝
function deepCopy (copyObj) {
// 用来记录已经拷贝过的属性值为对象的属性以及属性的值,解决递归循环引用对象的爆栈问题
const cache = {}
// 拷贝对象
function copy (obj) {
const target = {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// key为对象自身可枚举的属性
if (
Object.prototype.toString.call(obj[key]) === '[object Object]'
) {
// 属性值为对象
if (cache[obj[key]]) {
// 说明该属性已经被拷贝过一次,现在又拷贝,证明出现了循环引用
target[key] = cache[obj[key]]
} else {
cache[obj[key]] = obj[key]
target[key] = copy(obj[key])
}
} else {
target[key] = obj[key]
}
}
}
return target
}
return copy(copyObj)
}
测试案例
const obj1 = {a: 'a', b: {c: 'cc'},d:function(){}}
console.log('源对象: ', obj1) // 源对象: {a: "a", b: {c: "cc"}}
const copyObj1 = deepCopy(obj1)
console.log('拷贝后的目标对象: ', copyObj1) // 拷贝后的目标对象: {a: "a", b: {c: "cc"}}
console.log('-----改变目标对象的属性---------')
copyObj1.b = 'bb'
console.log('源对象: ', obj1) // 源对象: {a: "a", b: {c: "cc"}}
console.log('目标对象: ', copyObj1) // 目标对象: {a: "a", b: "bb"}
// 示例二, 对象存在循环引用
const objLoop = {}
const b = {objLoop}
objLoop.b = b
console.log('源对象: ', objLoop) // 源对象: {b: {objLoop: {b: {objLoop: {b: ...}}}}}
const copyObjLoop = deepCopy(objLoop)
console.log('目标对象: ', copyObjLoop) // 目标对象: {b: {objLoop: {b: {objLoop: {b: ...}}}}}
console.log('-----改变目标对象------')
copyObjLoop.b = 'bb'
console.log('源对象: ', objLoop) // 源对象: {b: {objLoop: {b: {objLoop: {b: ...}}}}}
console.log('目标对象: ', copyObjLoop) // 目标对象: {b: "bb"}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。