谈谈javascript中使用等式赋值带来的问题
序
这句标题原本是在国外的一个JavaScript规范中看到的,但是当时并没有引起足够的重视,直到最新的bug在JS中发现了连赋值操作的特性(坑)。
在网上搜索,找到一个非常好的平等分配的例子(来源1,来源2):
var a={ n :1 };a . x=a={ n :2 };console . log(a . x);//输出?答案是:
console . log(a . x);//undefined我不知道你说的对不对,但至少我说错了。
然后借此机会好好看看JS公司的作业。
分配顺序?
假设有一个代码:A=B=C;赋值语句的执行顺序是从右到左,所以问题在于:
是猜想1:b=c;a=C;
或者猜2:b=c;a=B;
我们都知道,如果两个对象同时指向一个对象,这个对象的修改是同步的,比如:
var a={ n :1 };var b=a;a . n=2;console . log(b);//对象{n: 2}所以我们可以根据这个特性来测试连续赋值的顺序。
根据猜想1,把c变成一个特定的对象,可以看到a的修改不会同步到b,因为分别执行第一行和第二行的时候创建了两个{n:1}对象。例如:
var b={ n :1 };var a={ n :1 };a . n=0;console . log(b);//对象{n: 1}根据猜想2,把c变成一个特定的对象,可以看到a的修改是同步到b的,因为a和b都同时引用一个对象,比如:
var b={ n :1 };var a=b;a . n=0;console . log(b);//对象{n: 0}测试实等式赋值:
风险值a,b;a=b={ n :1 };a . n=0;console . log(b);//可以看出对象{n: 0}与猜想2一致。如果有人认为这个测试不准确,可以再测试一次,使用ECMA5的setter和getter特性进行测试。
首先,setter和getter应用于变量名,而不是变量实际存储的对象,如下所示:
object . defineperoperty(window,' obj ',{ get : function(){ console . log(' getter!');}});var x=objobj//getter!undefinedx//未定义您可以看到只有obj输出“getter!"而x没有输出,所以用这个特性来测试。
偶数分配测试2:
object . defineperoperty(window,' obj ',{ get : function(){ console . log(' getter!');}});a=b=obj//getter!未定义
Getter再次证明C在A=B=C b=c中只被读取一次。
所以等式赋值的真正运算规则是B=C;a=B;也就是说,连续赋值是从右向左的,只有等号右边的表达式结果总是赋给等号左边的。
连续赋值可以分解写吗?
通过以上,我们可以看到连续赋值的真正规则,所以我们将回到文章开头的案例。如果我们按照上面的规则拆解连续赋值,会发现结果是不一样的,比如:
var a={ n :1 };a={ n :2 };a.x=aconsole . log(a . x);//Object {n: 2,x: Object}所以虽然连续赋值语句遵循从右到左依次赋值的规则,但还是不能拆开来写。为什么呢?
我猜:为了保证赋值语句的正确性,js会在一个赋值语句执行之前,取出所有要赋值的引用地址的副本,然后依次赋值。
所以,我认为这个代码是a . x=a={ n :2 };逻辑是:
1.在执行之前,a和a.x中的a的引用地址将首先被取出,该值指向{n:1}。
2.在内存{n:2}中创建一个新对象。
3.执行a={n:2},将A的引用从指向{n33601}改为指向新的{n33602}。
4.执行a.x=a,此时A已经指向了新的对象,但是a.x在执行之前保留了原来的引用,所以a.x还是指向了原来的{n:1}对象,所以在原来的对象上增加了一个属性X,其内容是{N33602},现在是A。
5.语句执行后,原对象从{n:1}变为{N33601,X3360 {N33602}},但由于没有人再次引用,原对象被GC回收。目前,A指向新对象{N33602}。
6.所以文章开头有运行结果,然后执行a.x自然是未定义的。
上述过程由序列号说明:
根据上述过程,可以看出,旧的a.x和新的a都指向新创建的对象{n:2},因此它们应该是全等的。
测试:
var a={ n :1 };var b=a;a . x=a={ n :2 };console . log(a===b . x);//真
因为我们增加了var b=a,也就是增加了对原对象的引用,所以在上面的第五步中不会释放,这就印证了上面的结论。
附言
通过了解这次连续赋值的特点,再回头看文章标题,似乎应该叫:
尽量不要使用JS的连续赋值操作,除非你真正了解它的内部机制和可能的后果。
版权声明:谈谈javascript中使用等式赋值带来的问题是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。