本文转载自   小小沧海博客

文章标题这句话原本是在国外某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!!!");}
});
var x=obj;
obj;//getter!!! undefined
x;//undefined

可以看到只有obj输出了“getter!!!”,而x没有输出,用此特性来测试。

连等赋值测试2:

Object.defineProperty(window,"obj",{get:function(){console.log("getter!!!");}
});
a=b=obj;//getter!!!  undefined

通过getter再次证实,在A=B=C中,C只被读取了一次。

所以,连等赋值真正的运算规则是  B = C; A = B;  即连续赋值是从右至左永远只取等号右边的表达式结果赋值到等号左侧。

连续赋值能拆开写么?

通过上面可以看到连续赋值的真正规则,那么再回归到文章开头的那个案例,如果按照上述规则将连续赋值拆开会发现结果不一样了,如:

var a={n:1};
a={n:2};
a.x=a;
console.log(a.x);//Object {n: 2, x: Object}

所以连续赋值语句虽然是遵从从右至左依次赋值的规则但依然不能将语句拆开来写,至于为什么

我猜测:js内部为了保证赋值语句的正确,会在一条赋值语句执行前,先把所有要赋值的引用地址取出一个副本,再依次赋值。

所以我认为这段代码  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了

上述过程按序号图示:

按照上述过程可以看出旧的a.x和新的a都指向新创建的对象{n:2},所以他们应该是全等的。

测试:

var a = {n:1};
var b = a;
a.x = a = {n:2};
console.log(a===b.x); //true

因为我们增加了var b=a,即将原对象增加了一条引用,所以在上述第5步时不会被释放,证实了上面的结论。

后记

通过这次了解了连续赋值的特点,再回过头看文章标题,似乎应该叫:

尽量不要使用JS的连续赋值操作,除非真的了解它的内部机制及可能会产生的后果。

原文链接-http://www.cnblogs.com/xxcanghai/p/4998076.h

a.x=a={n:1} JS中使用连等赋值操作相关推荐

  1. js 中对于 css 的变量操作(React也可)

    文章目录 前言 一.设置CSS变量? 二.读取变量 三.删除变量 总结 前言 主要讲js 中对于 css 的变量操作: 前端框架:antd框架 一.设置CSS变量? document.body.sty ...

  2. php mysql 变量赋值_mysql存储过程中变量的定义赋值操作

    一.变量的定义 mysql中变量定义用declare来定义一局部变量,该变量的使用范围只能在begin...end 块中使用,变量必须定义在复合语句的开头,并且是在其它语句之前,也可以同时申明多个变量 ...

  3. js中节点关系及相关操作

    1.节点关系 父节点 parentElement 所有子节点 children 第一个子节点 firstElementChild 最后一个子节点 lastElementChild 上一个兄弟节点 pr ...

  4. js中的cookie的读写操作

    cookie cookie是一小段信息,以键/值对的信息保存在计算机硬盘上的字符串, cookie存储容量大概在4kb,不同的浏览器厂家对cookie大小的限制有微微的差异:cookie主要的本质是& ...

  5. JS中字符串的创建、操作及其方法

    文章目录 前言 一.创建字符串 二.字符串的操作 三.字符串拼接 1.普通"+"拼接 2.模板字符串 四.字符串中的方法 1.charAt() 2.charCodeAt() 3.s ...

  6. js中数组的高逼格操作(filter、sort、map、reduce)

    说在前面的话 ES6全称ECMAScript 6.0, 成为JavaScript 的下一个版本标准.它提供了一些很牛逼的东西,使我们写的代码更加简洁.方便.比如模板字符串.箭头函数.promise.c ...

  7. JS中关于字符串返回的操作

    1.1 复习 1. 按钮不可用    disabled =  "disabled"  ||  true 2. setTimeout   只执行一次    setInterval   ...

  8. JS中给input框赋值

    两种方法(推荐使用第一种) 1.利用JQuery给input框赋值(使用前提是已经引入了jquery.js) <input type="text" id="name ...

  9. 微信小程序开发——JS中字符和数组的操作

    字符的操作 var word = "hello world" length字符串长度 let len = word.length trim去掉空格 word.trim() inde ...

最新文章

  1. mySQL之单表更新
  2. 树莓派模拟电路_9.树莓派3B+ PWM操作
  3. linux 64位 安装qt creator .run,Qt Creator安装
  4. C++静态成员和非静态成员的区别 及修饰
  5. clone是深拷贝还是浅拷贝_Python中的浅拷贝和深拷贝
  6. java将对象 缓存_ehcache java 对象缓存怎么实现
  7. Ant-Design-Vue和Icon按需加载方案 - JeecgBoot实战
  8. 龙腾世纪:起源(推荐一个可以用来英语学习的RPG游戏)
  9. Open3d之内部形状描述子ISS
  10. [机器学习]机器学习常用的模型评估方法
  11. 苹果 macOS 11 Big Sur初体验, 升还是不升?
  12. 全文检索(LuceneSolr)
  13. 离散数学第二版傅彦课后题答案_青年大最新答案第十季第四期答案 完整版题目和答案分享[多图]...
  14. FileZilla客户端使用遇到的问题
  15. 【前端】在vue项目中使用mixpanel记录用户访问量,5s内同一客户端记录一次
  16. arcgis中导入excel数据时显示没有注册类怎么解决?
  17. placement new和placement delete
  18. Sql Server利器sql prompt
  19. hss网元 java,EPC网络中网元HSS的英文全称是()。
  20. 数据库管理系统的层次结构--语言处理层

热门文章

  1. win7没有个性化如何把计算机放到桌面,win7桌面点右键没有个性化设置选项怎么办...
  2. 边缘计算机大会,视美泰边缘计算盒新品首发,“双”旗舰惊艳亮相2021 GECC全球边缘计算大会,为边缘计算场景增添新-文章-数字音视工程网DAV01.COM...
  3. memtest86+
  4. android录制10秒视频教程,快手怎样录制60秒视频 快手怎么录长视频教程
  5. 删除了mysql的root账户密码是什么_mysql误删root用户或者忘记root密码解决方法
  6. 华硕主板无盘启动bios设置_华硕影驰 bios设置,手把手教你华硕主板bios如何设置U盘启动...
  7. mui实现上下滑动控制显隐效果
  8. tensorflow的安装
  9. Unity 包体优化之png拆分为JPG和Alpha Mask
  10. unturned直连服务器开法,未变异者(Unturned)TP-link直连服开服方法图文介绍