文章标题这句话原本是在国外某JavaScript规范里看到的,当时并没有引起足够的重视,直到最近一次出现了bug发现JS里的连等赋值操作的特色(坑)。 网上搜索一番发现一个非常好的连等赋值的例子: 答案是: console.log(a.x); // undefined 不知道各位有没有答对,至少我是答错了。遂借此机会好好看看JS连等赋值是怎么回事 赋值顺序? 是猜想1: B = C; A = C; ? 还是猜想2: B = C; A = B; ? 我们都知道若两个对象同时指向一个对象,那么对这个对象的修改是同步的,如: 所以可以根据这个特性来测试连续赋值的顺序。 再按照猜想2,把C换成具体的对象,可以看到对a的修改同步到了b,因为a和b同时引用了一个对象,如: 测试真正的连等赋值: 可以看到是符合猜想2的,如果有人觉得这个测试不准确可以再来测试,使用ECMA5的setter和getter特性来测试。 首先setter和getter是应用于变量名的,而不是变量真正储存的对象,如下: 可以看到只有obj输出了“getter!!!”,而x没有输出,用此特性来测试。 连等赋值测试2: ![]() 通过getter再次证实,在A=B=C中,C只被读取了一次。 所以,连等赋值真正的运算规则是? B = C; A = B;? 连续赋值能拆开写么? 所以连续赋值语句虽然是遵从从右至左依次赋值的规则但依然不能将语句拆开来写,至于为什么? 所以我认为这段代码 a.x=a={n:2}; 的逻辑是: 1、在执行前,会先将a和a.x中的a的引用地址都取出来,此值他们都指向{n:1} 2、在内存中创建一个新对象{n:2} 3、执行a={n:2},将a的引用从指向{n:1}改为指向新的{n:2} 4、执行a.x=a,此时a已经指向了新对象,而a.x因为在执行前保留了原引用,所以a.x的a依然指向原先的{n:1}对象,所以给原对象新增一个属性x,内容为{n:2}也就是现在a 5、语句执行结束,原对象由{n:1}变成{n:1,x:{n:2}},而原对象因为无人再引用他,所以被GC回收,当前a指向新对象{n:2} 6、所以就有了文章开头的运行结果,再执行a.x,自然就是undefined了 上述过程按序号图示: 测试: 因为我们增加了var b=a,即将原对象增加了一条引用,所以在上述第5步时不会被释放,证实了上面的结论。 后记 通过这次了解了连续赋值的特点,再回过头看文章标题,似乎应该叫:尽量不要使用JS的连续赋值操作,除非真的了解它的内部机制及可能会产生的后果。 |
JS中连等赋值操作使用注意事项(a=b=c)
最新推荐文章于 2024-07-18 15:45:17 发布