一、先看问题
1 | var a = {n:1}; |
二、逐步分析
下面来分析下这段简单代码的工作步骤,从而进一步理解js引用类型“赋值”的工作方式。首先是:
1 | var a = {n:1}; |
在这里a指向了一个对象{n:1}(我们姑且称它为对象A),b指向了a所指向的对象,也就是说,在这时候a和b都是指向对象A的。这一步很好理解,接着继续看下一行非常重要的代码:
1 | 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):
接着继续执行
1 | 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: