Javascript连等赋值问题
起源于一段代码
1 2 3 4 5 |
var a = {n:1}; var b = a; // 持有a,以回查 a.x = a = {n:2}; console.log(a.x);// --> undefined console.log(b.x);// --> {n:2} |
为什么会出现这种结果,相关的讨论也不少,众说纷纭,不排除很多为了答案而答案的解析。
仔细整理分析之后,要理解这个情况需要明确两个知识点。
第一点:语句是从左到右依次解析的,对于运算符之间的每一个元素都是最高优先执行的,之后考虑运算符的优先级进行执行。
第二点:基本变量值和引用变量值的赋值是不一样的:
引用类型值的赋值拷贝,复制的是地址,基本类型变量赋值拷贝,复制的是值。简化逻辑如下图示:
刨根问底
关于第一个知识点需要重点说明下:
先举个例子,直接上代码了:()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
var a = 1; function fn1() { a = 2; return 3; } function fn2() { a = 3; return 3; } console.log( fn1() + a); // 输出 5 =3+2 // 重置一下a值, 不放心的话可以把上面a、fn1、fn2的代码再粘一遍 a = 1; console.log( a + fn1() ); // 输出 4 =1+3 a = 1; console.log( a + fn1() + a**fn2() ); // 输出 12 =1+3+2^3=1+3+8 a = 1; console.log( a + fn1() + a + fn2()**a ); // 输出 33 =1+3+2+3^3=1+3+2+27 |
对比分析以上代码的输出,不难得出,运算符的优先级是建立在从左到右依次确认参与运算元素的基础之上的。把代码中的最后一个运算拿出来解释一下:
a
值在经过fn1()
之后a=2
在没有运算到fn1()
之前还是保持了a=1
的原值,fn2()**2
幂运算是从右到左的计算,但是依旧不影响从左到右一次确认参与运算元素的操作,先执行fn2()
和a
值再进行幂运算最后再加起来,可以再试下a + fn1() + a + fn2()*fn1()*a
的值,输出值应该是24
,因为fn1()
把a
值又改称2
了。
第二点就不多解释了,感兴趣的可以参考[JavaScript赋值时的传值与传址]
问题解析
回过头来分析下开头的这句段代码。
对于语句:a.x = a = {n:2};
执行过程是这样的:
从左到右,确认要进行运算的元素a.x
,a对象是引用类型的Object数据,而且a
不存在属性x
那么为a分配x=undefined
,这时候b和a的值除了自身地址是完全一致的。
接下来发现a.x
右侧是=
操作,需要确认a={n:2}
的值,这是要把一个新的对象给a,意味着a要指向新的地址,和b指的地址已经不一样了。此时:a={n:2}; b={n:1,x:undefined}
。
最后一步就是对a.x
的赋值了,也就是让a.x
指向新a
最后结果就是a={n:2}; b={n:1; x: {n:2}}
分析结束