我们会在变量中存放对象,而引用类型的变量会存放内存地址。在这里会产生一系列出乎意料的结果,令人十分头疼。我也经过一番研究后才明白。
话不多说,先看以下代码:
题目1:
var user1 = {
name: "u1",
address: {
country:"中国",
city:"珠海"
}
};
var user2 = {
name: "u2",
address: user1.address
};
user2.name = "666";
user2.address.city = "深圳";
console.log(user1.name,user2.name);
console.log(user1.address.city,user2.address.city)
到底会输出什么?纠结点在于以下两行代码有没有改变user1里的属性值。
user2.name = "666";
user2.address.city = "深圳";
解决思路
遇到这种情况,初学者最好的方法莫过于画图。我们一步一步来,先看user1的声明过程
var user1 = {
name: "u1",
address: {
country:"中国",
city:"珠海"
}
};
在这一阶段,会创建一个user1的房间(内存空间),用于存放对象的内容,指向属性分别为name和address。同时address又是一个新的对象。图示如下:
OK!接下来往下看,下面的代码创建了一个user2对象,属性值仍然有两个,分别是name和address,但是不同的是,address并没有产生新的地址。也就是说,这两个address指向的地址一样!持有相同的引用。
var user2 = {
name: "u2",
address: user1.address
};
我们用图来表示,如下所示:
敲黑板!重点来了,我们对user2的属性值动手脚
user2.name = "666";
user2.address.city = "深圳";
非常明显,user2的name属性是属于他自己的,所以他修改了name,并不会影响到user1.name;与此同时,由于user2和user1指向同一个address对象,持有相同的引用,所以user2修改了address,user1也会受到影响。如下图所示:
分析完毕,我们到浏览器测试一下!!!结果和我们分析一致。
到这里不知道大家听懂了吗?画图能够很方便地理解这个问题。我们再来一道比较难的题目。
题目2:
var obj1 = {
a: "123",
b: "456",
sub: {
s1: "abc",
s2: "bcd"
}
};
var temp = obj1.sub;
var obj2 = obj1;
obj2.sub = {
s1: "s",
s2: "ddd"
};
console.log(obj1.sub.s1, obj2.sub.s1, temp.s1);
console.log(window);
这一道题,多了一个变量temp,但是原理和解题思路是一样的。如下图所示:
Step1: 定义了一个新的对象,开辟了内存空间用于存储对象的内容。
var obj1 = {
a: "123",
b: "456",
sub: {
s1: "abc",
s2: "bcd"
}
};
Step2: 定义了一个新的变量,赋值就是复制黏贴,这么理解的话,相当于又复制了一份sub,temp指向他
var temp = obj1.sub;
Step3: 定义了一个新的变量obj2,赋值就是复制黏贴,这么理解的话,相当于又复制了一份obj1,其余不变。
var obj2 = obj1;
Step4: 做到这里,我们发现离真相已经不远了,在接下来的代码,obj2修改sub里的属性值,就相当于obj1的sub也会改变。
obj2.sub = {
s1: "s",
s2: "ddd"
};
修改完如下图所示:
浏览器测试,结果如我们预料,这一修改并没有影响到temp的属性值,所以输出如下:
小贴士:
-
出现“=”就是赋值,把右边的赋值给左边,相当于复制了一个一摸一样的,左边的变量指向的地址和右边的变量一样,持有相同的引用
-
出现{}我们就可以判断一个新的对象产生,内存用来存储对象中的内容