面试题

面试题目1 – 详细讲解

var a = {"x": 1};
var b = a;
a.x = 2;
b.x; //2

a = {"x":3};
b.x;//2
a.x = 4;
b.x;//2
详细解释一下每一个b.x的值是怎么来的?

 

 

首先定义一个对象a,有一个属性x,值为1。接着让b = a,这一步的结果就是a和b指向了同一个对象。

 

在内存中,对象的存储和基本数据类型不同。基本数据类型直接保存在栈里,a = 1,b = 1,在栈里会保存两份1,分别赋值给a和b。修改a或b,对另一个变量不会有什么影响。如下图:

 

 

对象则不然,变量a和b如果被赋值对象,a和b实际上保存的只是对象的地址,而且a和b还是被存储在栈里,同时a和b的地址是相同的。但对象是在堆里保存,且只保存一份,对象的地址就是a和b的值,a和b都指向同一个对象。这与C里面的指针类似,修改指向同一个对象的任何一个变量,与之引用同一对象变量很快就会发生同样的变化。如下图:

 

所以现在的情况就是,a和b都指向了堆中的一个对象,这个对象的属性x值是1。那么a.x = 1,b.x自然也等于1。

1

a.x = 2

接下来发生一件事情,a修改了对象的x属性为2,这个变化反映到了堆中:

 

看,a和b还是指向了同一个对象,只不过对象中的x属性值变成了2。这一变化b很快就发现了,所以你再去访问b.x,实际上就是访问堆中的对象的x属性,也就是2。

1

a = {"x":3};

再后来,为a赋值了一个新的对象,虽然它也有一个属性x,但它确实是一个新对象!那么内存堆中发生了什么呢?首先,堆中原有的对象(x = 2的那个)还在那里。因为新建了一个对象(x = 3的),堆中就会出现一个新的对象,与原来的对象毫无关系。同时,b并没有变化,它还指向原有的对象(x = 2),但a指向原来的对象的地址却发生了变化,它指向了x = 3的这个新对象。堆中情况如下:

 

如上图,a的地址变了,同时a和原来的对象也没有指向关系了,它指向了新的对象,这个新对象的x = 3。而b对象没有任何变化,它还坚守着自己的对象,对象的x属性是2。

1

a.x = 4;

接着修改了a的x属性为4,参考前面的描述,我们可以知道堆的变化如下:

 

瞧,a的x属性变成了4,但b和a已经没有关系了,所以b的x属性还是2。

 

PS:以上地址什么的,都是随便写的,实际内存中肯定不是这些数字。

 

面试题目2 – 重点讲解

代码如下:

<script>

var a = {n:1};

var b = a; 

a.x = a = {n:2};

console.log(a.x);// --> undefined

console.log(b.x);// --> [object Object]

</script>

上面的例子看似简单,但结果并不好了解,很容易把人们给想绕了——“a.x不是指向对象a了么?为啥log(a.x)是undefined?”、“b.x不是应该跟a.x是一样的么?为啥log出来居然有2个对象”

当然各位可以先自行理解一下,若能看出其中的原因和工作机理自然就无须继续往下看啦。

下面来分析下这段简单代码的工作步骤,从而进一步理解js引用类型“赋值”的工作方式。

首先是

var a = {n:1};  
var b = a;

在这里a指向了一个对象{n:1}(我们姑且称它为对象A),b指向了a所指向的对象,也就是说,在这时候a和b都是指向对象A的:

 

这一步很好理解,接着继续看下一行非常重要的代码:

a.x = a = {n:2};

我们知道js的赋值运算顺序永远都是从右往左的,不过由于“.”是优先级最高的运算符,所以这行代码先“计算”了a.x。

这时候发生了这个事情——a指向的对象{n:1}新增了属性x(虽然这个x是undefined的):

 

从图上可以看到,由于b跟a一样是指向对象A的,要表示A的x属性除了用a.x,自然也可以使用b.x来表示了。

接着,依循“从右往左”的赋值运算顺序先执行 a={n:2} ,这时候,a指向的对象发生了改变,变成了新对象{n:2}(我们称为对象B):

 

 

接着继续执行 a.x=a,很多人会认为这里是“对象B也新增了一个属性x,并指向对象B自己”

但实际上并非如此,由于( .  运算符最先计算)一开始js已经先计算了a.x,便已经解析了这个a.x是对象A的x,所以在同一条公式的情况下再回来给a.x赋值,也不会说重新解析这个a.x为对象B的x。

所以 a.x=a 应理解为对象A的属性x指向了对象B:

 

 

 

那么这时候结果就显而易见了。当console.log(a.x)的时候,a是指向对象B的,但对象B没有属性x。没关系,当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止。但当查找到达原型链的顶部 - 也就是 Object.prototype - 仍然没有找到指定的属性B.prototype.x,自然也就输出undefined;

而在console.log(b.x)的时候,由于b.x表示对象A的x属性,该属性是指向对象B,自然也输出了[object Object]了,注意这里的[object Object]可不是2个对象的意思,对象的字符串形式,是隐式调用了Object对象的toString()方法,形式是:"[object Object]"。所以[object Object]表示的就只是一个对象罢了:)

面试题2

JavaScript值类型和引用类型有哪些

(1)值类型:数值、布尔值、null、undefined。

(2)引用类型:对象、数组、函数。

posted @ 2017-12-06 12:08  前端极客  阅读(234)  评论(0编辑  收藏  举报