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

一、引子

复制代码 代码如下:

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}。如下图


四:解惑

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

复制代码 代码如下:

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

时间: 2024-09-19 23:35:23

写了10年的Javascript也未必全了解的连续赋值运算_javascript技巧的相关文章

写出更好的JavaScript程序之undefined篇(中)_javascript技巧

写在前面的依然是消歧义声明:本文中JavaScript是指一般意义上的JavaScript,并不只限定"自称是JavaScript"的运行环境:"全局变量"和"全局对象的属性"是指同样的东西,只是因为要配合上下文才用了不同的说法,正文中我就不再另外解释了:"声明"指通过"var"语句声明变量和/或对函数及其签名的定义:"变量"指通过"var"语句声明过或者在函数体中试

JavaScript九九乘法口诀表的简单实现_javascript技巧

先来看看效果图 JavaScript示例代码 <script type="text/javascript"> var body = document.getElementsByTagName('body')[0]; var wrap = document.createElement('div'); wrap.id = 'wrap'; body.appendChild(wrap); var wrap = document.getElementById('wrap'); for

用JavaScript仿PS里的羽化效果代码_javascript技巧

复制代码 代码如下: <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <title>用JavaScript防PS里的羽化效果代码 - www.jb51.net</title> </head> <body onload=setValues()> <center&g

javascript实现下雪效果【实例代码】_javascript技巧

原理 : 1.js动态创建DIV,指定CLASS类设置不同的背景图样式显示不同的雪花效果. 2.js获取创建的DIV并改变其top属性值,当下落的高度大于屏幕高后删除该移动div 3.好像不够完善勿喷 HTML代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>雪花飞舞</title> <lin

javascript实现网页背景烟花效果的方法_javascript技巧

本文实例讲述了javascript实现网页背景烟花效果的方法.分享给大家供大家参考.具体如下: 这里的网页背景烟花爆炸特效,不用说是用Js实现的,配合黑色背景效果最好,五颜六色的烟花效果,四散的烟花效果,以前发过一些网页上的烟花特效,本款类似,但代码更简洁. 运行效果如下图所示: 具体代码如下: <html> <head> <title>背景的烟花效果</title> <style type="text/css"> <!

html5+javascript实现简单上传的注意细节_javascript技巧

简单记录下今早做H5上传中一些代码还有坑 一.展示 因为前端上传文件是必须通过form表单的,不能使用ajax,这样的话一个移动页面放入一个type为file的input真心不怎么好看,如下图,很挫有没有 解决办法找了下,PC上有些是把这个input换成flash,采用jquery的工具库比如uploadify来做,但是移动端大部分浏览器是不支持flash的.所以最后采用的办法还是用form表单的形式,只是把这个form和input的透明度设置为0,让它们和准备显示的内容同时在一个div中,显示

javascript+HTML5自定义元素播放焦点图动画_javascript技巧

这是一款基于HTML5的焦点图动画,它和其他焦点图不同的地方在于,它播放的不仅仅是图片,而是可以自定义控制的网页元素.它不仅在图片间切换有过渡动画效果,而且在切换时图片中的元素也将出现动画效果,比如图中的文字移动.打散.重新组合等,这款HTML5动画图片播放器算得上是高端大气上档次. 效果图: HTML代码 <div class="parallax-bg" id="slider-wrap"> <div class="slider para

javascript拖拽应用实例(二)_javascript技巧

经常在网站别人的网站的注册页中看到一个拖拽验证的效果,就是它的验证码刚开始不出来,而是有一个拖拽的条,你必须将这个拖拽条拖到底,验证码才出来,说了感觉跟没说一样,你还是不理解,好吧,我给个图你看看: 这个是在万网的注册页中所截的图,大概的效果就是,当拖动那个拖拽框时,如果拖拽框没有拖到最右边,则拖拽框会移动到初始位置,如果拖动到最右边,则拖拽框显示为对勾,中间的文字也变了,但是我试了一下,他的验证码的框没有出来,不知道是改了还是怎么的,我没有继续点击确定往下进行,那不是我们要讲的重点,我就在他的

Javascript 数组添加一个 indexOf 方法的实现代码_javascript技巧

[Ctrl+A 全选 注:如需引入外部Js需刷新才能执行] 运行以上代码,即可.如果大家想看的是 javascript indexOf的使用方法,请看下面的文章javascript indexOf函数使用说明JavaScript indexOf忽略大小写_javascript技巧