JS下的链式赋值
·
2 min read
今天看到群里发了一道JS基础题,以为很简单,但是不小心还做错了,于是这里Mark下。
var user = {
n: 1
};
user.x = user = {
n: 2
};
console.log(user.x);
错误分析
错误的以为等价于如下代码
var user = {
n: 1
};
user = {
n: 2
};
user.x = user;
console.log(user.x);
/**
* {n: 2, x: {…}}
* /
浏览器或者Node下执行,发现正确结果应该是undefined
继续错误分析
我重新翻了下JS的赋值运算符。针对链式赋值
Chaining the assignment operator is possible in order to assign a single value to multiple variables
也就是说实际上JS做的事是将一个值分别赋给了多个变量。即a=b=c应该等价于b=c;a=c;
因此上述代码等价代码如下
var user = {
n: 1
};
user = {
n: 2
};
user.x = {
n: 2
};
console.log(user.x);
心想,这回总该对了吧,浏览器运行发现结果是{n: 2}
还是不对,呃呃呃,问题在哪?- 成员访问点运算符。
正确分析
成员访问点运算符的优先级是最高的
因此重新再分析代码
var user = {
n: 1
};
user.x = {
n: 2
};
user = {
n: 2
};
console.log(user.x);
/**
* user.x这时指向的是一开始的user,将其看成1
* {n:2} 作为新的user,即2
* {n:2}赋值给1的x
* 最后打印2的x,没有这个属性,因此undefined
*
* 其实还是先user后user.x但是不一个user
*/
这么简单的题,说实话,挺坑的。不过也暴露了基础不扎实,同时自信品品这道题好几个细节点。
点运算法符优先级高于赋值运算符
链赋值基本逻辑是1个值同时赋给多个变量,并且赋值顺序是自右向左,这点其实也可以做个实验来证明,比如使用Proxy代理对象即可
var superman = { name: 'clark' }; var batman = {}; var flashman = {}; const batmanProxy = new Proxy(batman, { set: function (target, key, value) { console.log(`batman: ${key} set from ${target[key]} to ${value}`); target[key] = value; return true; } }); const flashmanProxy = new Proxy(flashman, { set: function (target, key, value) { console.log(`flashman: ${key} set from ${target[key]} to ${value}`); target[key] = value; return true; }, get: function (target, key) { console.log(`flashman: ${key} get from ${target[key]}`); return target[key]; } }); batmanProxy.name = flashmanProxy.name = superman.name;
以上代码打印会发现,首先被调用的set方法是flashman的,同时注意,以上并不等价于
batmanProxy.name = flashmanProxy.name = superman.name;
因为flashmanProxy的get方法并没被调用对象赋值是地址赋值
写在最后
问题简单但很基础,继续学习,继续搬砖。