谈谈谈谈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);//Object {n: 2}
所以可以根据这个特性来测试连续赋值的顺序。
按照猜想1,把C换成具体的对象,可以看到对a的修改不会同步到b上,因为在执行第一行和第二行时分别创建了两个 {n:1} 对
象。如:
var b={n:1};
var a={n:1};
a.n=0;
console.log(b);//Object {n: 1}
再按照猜想2,把C换成具体的对象,可以看到对a的修改同步到了b,因为a和b同时引用了一个对象,如:
var b={n:1};
var a=b;
a.n=0;
console.log(b);//Object {n: 0}
测试真正的连等赋值:
var a,b;
a=b={n:1};
a.n=0;
console.log(b);//Object {n: 0}
可以看到是符合猜想2的,如果有人觉得这个测试不准确可以再来测试,使用ECMA5的setter和getter特性来测试。
首先setter和getter是应用于变量名的,而不是变量真正储存的对象,如下:
Object.defineProperty(window,"obj",{
get:function(){
console.log("getter!!!");
}
});