这里先来整理一下对象的拷贝
我们都知道,对象是个复杂类型,这个变量就只是个指针。举个例子
var a=new String("abc")
var b=new String("abc")
console.log(a==b) //false
变量a和变量b是不相等的,因为他们指向的不是同一个对象。
console.log({}=={}) //false
console.log({a:1}=={a:1}) //false
对象的复制操作呢?可以直接变量赋值么?
var a={age:18}
var b=a
console.log(b) // {age:18}
console.log(a==b) //true
注意看,这里是不是很奇怪,刚刚我们操作console.log({a:1}=={a:1})结果是false 现在 console.log(a==b),结果居然是true.
这说明什么?这表示变量a和变量b指向的都是同一个内存地址,就是存放{a:1}的地址。
b.age=20
console.log(b.age) //20
console.log(a.age) //20
当我们改变了b.age的值之后,果然a.age的值也发生了变化。很明显,这样子的拷贝方式不能接受
直接复制不可取,那换一种方式呢?我们定义一个函数,循环的遍历一下。
function copy(obj){
var res={}
for(var i in obj){
if(obj.hasOwnProperty(i)){
res[i]=obj[i]
}
}
return res
}
var obj1={age:18}
var obj2=copy(obj1)
console.log(obj2) //{age:18}
我们对这个返回的新数操作一下,看看结果如何
obj2.age=20
console.log(obj1.age) //18
console.log(obj2.age) //20
这样子看起来,改变了obj2的 a 属性的值,obj1的 a 的的属性的值没有变化,这样子是不是就可以了呢?
我们把这个obj1数组再变化一下。
obj1 = {
age: 18,
position: ["北京", "广州", "上海"],
name: {
first: "lily",
last: "lucy"
}
}
此时的onj1不再是一个简单的对象了,他的属性有的是数组,有的是对象 。再操作一下
obj2.position[0]="深圳"
console.log(obj1.position) //["深圳","广州","上海"]
console.log(obj2.position) //["深圳","广州","上海"]
我们改变了obj2的 position[0]的值,把 “北京” 变成了 “深圳” ,结果,obj1和obj2都发生了改变。
那么问题来了,为什么改变 age 和改变 position 的结果是不一样呢?来看看对象obj1
var obj1 = {
age: 18,
position: ["北京", "广州", "上海"],
name: {
first: "lily",
last: "lucy"
}
}
当我们循环遍历对象a的属性。分开来分析
第一步,遍历属性age,把这个age赋值到obj2对象中去, 由于age就是个基本类型的变量,值为18,这就相当于 var a=18 b=a,因此obj2中的age保存的就是18
这里要和 var a={age:18} b=a 区别开来,这里的赋值是b=a, 是把 a赋值给b这是一个引用 ,而上面是把 obj1 的属性age 赋值给 obj2的属性age,这个age就是一个基本类型18
你要分清楚,赋过去的值,到底是一个基本类型还是一个引用
第二步 ,把obj1的position属性赋值给obj2,position指向的是一个数组,也就是说,传递给obj2的position和obj1的position指向的都是同一个地址.
同理,当我们赋值name属性的时候,这个属性是对一个对象的引用,也是一个指针。
我们来尝试改进一下,把 position 和 name:这两个引用属性,再调用这个函数操作,可否?
function find(copy,orig) {
var copy=copy||{}
for (var i in orig) {
if (typeof orig[i] === 'object') {
copy[i] = orig[i].constructor === Array ? [] : {}
find(copy[i],orig[i])
}else{
copy[i]=orig[i]
}
}
}
var obj1 = {
age: 18,
position: ["北京", "广州", "上海"],
name: {
first: "lily",
last: "lucy"
}
}
var obj2={sex:"girl"}
find(obj2,obj1)
再来测试一下,看看这个函数能否满足深复制的要求
obj2.name.first="mark"
console.log(obj1.name) //{first: "lily", last: "lucy"}
console.log(obj2.name) //{first: "mark", last: "lucy"}
obj2.position[0]="海南"
console.log(obj1.position) //["北京", "广州", "上海"]
console.log(obj2.position) //["海南", "广州", "上海"]
可以看到,这样子复制是完成了的.我们再来测试一下。多包裹几层,看看是否可以
var obj1 = {
age: 18,
position: ["北京", "广州", "上海"],
name: {
first:{
a:1,
b:2
},
last: "lucy"
}
}
var obj2={sex:"girl"}
find(obj2,obj1)
obj2.name.first.a=7
console.log(obj1.name.first) //{a: 1, b: 2}
console.log(obj2.name.first) //{a: 7, b: 2}
由于是递归的调用了这个拷贝函数,无论你的对象嵌套的层次有多么的深,总是可以保证拷贝成功的。
这里还有一个问题需要注意的,放到下一章节,点击这里查看下一章节