写在前面
此系列来源于开源项目:前端 100 问:能搞懂 80%的请把简历给我
为了备战 2021 春招
每天一题,督促自己
从多方面多角度总结答案,丰富知识
输出以下代码的执行结果并解释为什么
简书整合地址:前端 100 问
正文回答
题目
var a = { n: 1 };
var b = a;
a.x = a = { n: 2 };
console.log(a.x);
console.log(b.x);
// undefined;
// {
// n: 2;
// }
首先,a 和 b 同时引用了{n:2}
对象,接着执行到 a.x = a = {n:2}
语句,尽管赋值是从右到左的没错,但是.
的优先级比=要高,所以这里首先执行 a.x
,相当于为 a(或者 b)所指向的{n:1}
对象新增了一个属性 x,即此时对象将变为{n:1;x:undefined}
。
之后按正常情况,从右到左进行赋值,此时执行 a ={n:2}
的时候,a 的引用改变,指向了新对象{n:2}
,而 b 依然指向的是旧对象。
之后执行 a.x = {n:2}
的时候,并不会重新解析一遍 a,而是沿用最初解析 a.x
时候的 a,也即旧对象,故此时旧对象的 x 的值为{n:2}
,旧对象为 {n:1;x:{n:2}}
,它被 b
引用着。
后面输出 a.x
的时候,又要解析 a 了,此时的 a 是指向新对象的 a,而这个新对象是没有 x 属性的,故访问时输出 undefined
;而访问 b.x 的时候,将输出旧对象的 x 的值,即{n:2}
。
在引擎从左到右计算表达式的过程中,尽管可能遇见类似 a.x
这样本不存在的属性,但无论如何,都会存在 {"base": a, "name": "x", ...}
这样的数据结构,而在后续真正对 x 进行 读写 的时候,这个 x
才会得到创建。
这个代码块所做的事情,实际上是向旧有对象添加一个指向新对象的属性,并且如果我们想要在后续仍然持有对旧对象的访问,可以在赋值覆盖之前新建一个指向旧对象的变量。
考点
- 点的优先级大于等号的优先级
- 对象以指针的形式进行存储,每个新对象都是一份新的存储地址