写了10年的Javascript也未必全了解的连续赋值运算


Posted in Javascript onMarch 25, 2011

一、引子

var a = {n:1}; 
a.x = a = {n:2}; 
alert(a.x); // --> undefined

这是蔡蔡在看 jQuery源码 时发现这种写法的。以上第二句 a.x = a = {n:2} 是一个连续赋值表达式。这个连续赋值表达式在引擎内部究竟发生了什么?是如何解释的?

二、猜想

猜想1:从左到右赋值,a.x 先赋值为{n:2},但随后 a 赋值为 {n:2},即 a 被重写了,值为 {n:2},新的 a 没有 x属性,因此为undefined。步骤如下
1, a.x = {n:2};
2, a = {n:2};
这种解释得出的结果与实际运行结果一致,貌似是对的。注意猜想1中 a.x 被赋值过。
猜想2:从右到左赋值,a 先赋值为{n:2},a.x 发现 a 被重写后(之前a是{a:1}),a.x = {n:2} 引擎限制a.x赋值,忽略了。步骤如下:
1, a = {n:2};
2, a.x 未被赋值{n:2}
等价于 a.x = (a = {n:2}),即执行了第一步,这样也能解释a.x为undefined了。注意猜想2中a.x压根没被赋值过。

三、证明

上面两种猜想相信多数人都有,群里讨论呆呆认为是猜想1, 我认为是猜想2。其实都错了。我忽略了引用的关系。如下,加一个变量b,指向a。

var a = {n:1}; 
var b = a; // 暂存a 
a.x = a = {n:2}; 
alert(a.x);// --> undefined 
alert(b.x);// --> [object Object]

发现a.x仍然是undefined,神奇的是 b.x 并未被赋值过(比如:b.x={n:2}),却变成了[object Object]。b 是指向 a({n:1})的,只有a.x = {n:2}执行了才说明b是有x属性的。实际执行过程:从右到左,a 先被赋值为{n:2},随后a.x被赋值{n:2}。
1, a = {n:2};
2, a.x = {n:2};
等价于
a.x = (a = {n:2});
与猜想2的区别在于a.x 被赋值了,猜想2中并未赋值。最重要的区别,第一步 a = {n:2} 的 a 指向的是新的对象{n:2} , 第二步 a.x = {n:2} 中的 a 是 {a:1}。即在这个连等语句
a.x = a = {n:2};

a.x 中的a指向的是 {n:1},a 指向的是 {n:2}。如下图

写了10年的Javascript也未必全了解的连续赋值运算
四:解惑

这篇写完,或许部分人看完还是晕晕的。因为里面的文字描述实在是绕口。最初我在理解这个连等赋值语句时

var a = {n:1}; 
a.x = a = {n:2};

认为引擎会限制a.x的重写(a被重写后),实际却不是这样的。指向的对象已经不同了。引擎也没有限制a.x={n:2}的重写。
谢谢所有参与讨论的人:蔡蔡、呆呆、儒儒。这个问题最早是蔡蔡提出的。儒儒在 菜鸟灰呀灰 群里每次的讨论都那么投入,认真,哪怕是别人提出的话题。

五:结束

呵,以另一个连续赋值题结束。fun执行后,这里的 变量 b 溢出到fun外成为了全局变量。想到了吗?

function fun(){ 
var a = b = 5; 
} 
fun(); 
alert(typeof a); // --> undefined 
alert(typeof b); // --> number
Javascript 相关文章推荐
JavaScript的parseInt 进制问题
May 07 Javascript
基于jQuery的星级评分插件
Aug 12 Javascript
Jquery中巧用Ajax的beforeSend方法
Jan 20 Javascript
基于AngularJs + Bootstrap + AngularStrap相结合实现省市区联动代码
May 30 Javascript
利用yarn代替npm管理前端项目模块依赖的方法详解
Sep 04 Javascript
详解Angular5路由传值方式及其相关问题
Apr 28 Javascript
angularjs 的数据绑定实现原理
Jul 02 Javascript
Vue弹出菜单功能的实现代码
Sep 12 Javascript
深入理解Vue.js轻量高效的前端组件化方案
Dec 10 Javascript
基于vue--key值的特殊用处详解
Jul 31 Javascript
js实现带有动画的返回顶部
Aug 09 Javascript
谈谈node.js中的模块系统
Sep 01 Javascript
js 实现图片预加载(js操作 Image对象属性complete ,事件onload 异步加载图片)
Mar 25 #Javascript
基于jquery的3d效果实现代码
Mar 23 #Javascript
jquery 操作表格实现代码(多种操作打包)
Mar 20 #Javascript
jQuery实现的Email中的收件人效果(按del键删除)
Mar 20 #Javascript
jquery图片上下tab切换效果
Mar 18 #Javascript
javascript一些实用技巧小结
Mar 18 #Javascript
jquery获取下拉列表的值为null的解决方法
Mar 18 #Javascript
You might like
PHP中foreach循环中使用引用要注意的地方
2011/01/02 PHP
PHP导入Excel到MySQL的方法
2011/04/23 PHP
Laravel如何使用Redis共享Session
2018/02/23 PHP
PHP使用redis位图bitMap 实现签到功能
2019/10/08 PHP
dreamweaver 安装Jquery智能提示
2011/04/02 Javascript
30个最好的jQuery 灯箱插件分享
2011/04/25 Javascript
基于JavaScript实现继承机制之原型链(prototype chaining)的详解
2013/05/07 Javascript
Area 区域实现post提交数据的js写法
2014/04/22 Javascript
JavaScript 学习笔记之基础中的基础
2015/01/13 Javascript
简述JavaScript的正则表达式中test()方法的使用
2015/06/16 Javascript
js判断手机号运营商的方法
2015/10/23 Javascript
设置cookie指定时间失效(实例代码)
2017/05/28 Javascript
jquery请求servlet实现ajax异步请求的示例
2017/06/03 jQuery
js前端导出Excel的方法
2017/11/01 Javascript
vue如何解决循环引用组件报错的问题
2018/09/22 Javascript
layer关闭弹出窗口触发表单提交问题的处理方法
2019/09/25 Javascript
在vue中获取wangeditor的html和text的操作
2020/10/23 Javascript
[02:40]DOTA2英雄基础教程 炼金术士
2013/12/23 DOTA
[56:17]NB vs Infamous 2019国际邀请赛淘汰赛 败者组 BO3 第三场 8.22
2019/09/05 DOTA
[01:23:24]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Elephant BO3 第三场 2月7日
2021/03/11 DOTA
Python实现动态添加类的属性或成员函数的解决方法
2014/07/16 Python
python字符串连接方法分析
2016/04/12 Python
Ubuntu20.04环境安装tensorflow2的方法步骤
2021/01/29 Python
python实现银行账户系统
2021/02/22 Python
五款漂亮的纯CSS3动画按钮的实例教程
2014/11/21 HTML / CSS
CSS3制作hover下划线动画
2017/03/27 HTML / CSS
Pretty Green美国:英式摇滚服饰风格代表品牌之一
2019/01/23 全球购物
Schecker荷兰:狗狗用品和配件
2019/06/06 全球购物
YII2 全局异常处理深入讲解
2021/03/24 PHP
五年级学生评语
2014/04/22 职场文书
学雷锋志愿者活动方案
2014/08/21 职场文书
教师自我剖析材料范文
2014/09/30 职场文书
酒会邀请函
2015/01/31 职场文书
交通安全教育心得体会
2016/01/15 职场文书
《抽屉原理》教学反思
2016/02/20 职场文书
给numpy.array增加维度的超简单方法
2021/06/02 Python