【转】千万不要在JS中使用连等赋值操作
千万不要在JS中使用连等赋值操作
目录
前言
文章标题这句话原本是在国外某JavaScript规范里看到的,当时并没有引起足够的重视,直到最近一次出现了bug发现JS里的连等赋值操作的特色(坑)。
网上搜索一番发现一个非常好的连等赋值的(来源1,来源2)例子:
var a = {n:1};
a.x = a = {n:2};
console.log(a.x); // 输出?
答案是:
console.log(a.x); // undefined
console.log(a.x); // undefined
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.html
如果您认为本文对得起您所阅读他所花的时间,欢迎点击右下角↘ 推荐。您的支持是我继续写作最大的动力,谢谢
作者:小小沧海
出处:http://www.cnblogs.com/xxcanghai/
本文地址:http://www.cnblogs.com/xxcanghai/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
【转】千万不要在JS中使用连等赋值操作的更多相关文章
- 千万不要在JS中使用连等赋值操作
前言 文章标题这句话原本是在国外某JavaScript规范里看到的,当时并没有引起足够的重视,直到最近一次出现了bug发现JS里的连等赋值操作的特色(坑). 网上搜索一番发现一个非常好的连等赋值的(来 ...
- Node.js 中MongoDB的基本接口操作
Node.js 中MongoDB的基本接口操作 连接数据库 安装mongodb模块 导入mongodb模块 调用connect方法 文档的增删改查操作 插入文档 方法: db.collection(& ...
- JS中基本window.document对象操作以及常用事件!
一.找到元素 1.document.getELementById("id"):根据id找,最多找一个. var a=document.getELementById("id ...
- JS中的事件以及DOM 操作
[DOM树节点] DOM节点分为三大节点:元素节点,文本节点,属性节点. 文本节点,属性节点为元素节点的两个子节点通过getElment系列方法,可以去到元素节点 [查看节点] 1 document. ...
- JS中的DOM— —节点以及操作
DOM操作在JS中可以说是非常常见了吧,很多网页的小功能的实现,比如一些元素的增删操作等都可以用JS来实现.那么在DOM中我们需要知道些什么才能完成一些功能的实现呢?今天这篇文章就先简单的带大家入一下 ...
- js中一些对字符串的操作等
看代码时候,发现一些写的很好的js对字符串的操作,记录下来,持续更新等>... js trim()的实现: function trim(string){ return string.replac ...
- 探究JS中的连等赋值问题
一.引子 最近在看别人的博客时无意中看到一个这样的问题 var a = {n: 1}; var b = a; a.x = a = {n:2}; console.log(a.x); //undefine ...
- JS中的常用的代码操作
本文件介绍常用的js代码的DOM操作.CSS操作.对象(Object对象.Array对象.Number对象.String对象.Math对象.JSON对象和Console对象)操作说明. 一.DOM树的 ...
- js中三个对数组操作的函数 indexOf()方法 filter筛选 forEach遍历 map遍历
indexOf()方法 indexOf()方法返回在该数组中第一个找到的元素位置,如果它不存在则返回-1. 不使用indexOf时 var arr = ['apple','orange','pea ...
随机推荐
- Servlet 笔记-生命周期
Servlet 生命周期可被定义为从创建直到毁灭的整个过程.以下是 Servlet 遵循的过程: Servlet 通过调用 init () 方法进行初始化. Servlet 调用 service() ...
- 实现响应式——Bootstrap的删格系统详解
Bootstrap 今天和大家一起学习如今很流行的前端框架之一,Bootstrap框架. 前言 今天带大家看看Bootstrap框架,其实我呢主要还是用里面的删格系统,单单这个删格系统就比较强大了.其 ...
- 视频加载logo 2
推荐这个网站 http://www.flaticon.com/ http://www.flaticon.com/search?word=spinner 旋转图标 http://www.flatico ...
- 基于Vue.js的大型报告页项目实现过程及问题总结(一)
今年5月份的时候做了一个测评报告项目,需要在网页正常显示的同时且可打印为pdf,当时的技术方案采用jquery+template的方式,因为是固定模板所以并没有考虑报告的模块化区分,九月底产品提出新的 ...
- 前端的UI设计与交互之色彩篇
一.颜色Red热情.警示 Green成功.通过.安全 Blue专业.科技 Pink典雅.明快.女性 Orange醒目.温暖 Purple高雅.浪漫 Yellow活力.提示 Cyan清新.冷静.结构化 ...
- jquery getScript动态加载JS方法改进详解[转载]
转载自http://www.jb51.net/article/31973.htm 有许多朋友需要使用getScript方法动态加载JS,本文将详细介绍此功能的实现方法 $.getScript( ...
- javaSE基础
变量 1.变量就是数据存储空间的表示. 2.标识符命名规则:变量名=首字母+其余部分 ①首字母:字母.下划线.“$”符号(开头) ②其余部分:数字.字母.下划线“$” ③应避开关键字:int int ...
- ACID 数据库正确执行四要素
ACID:数据库事务正确执行所必须满足的四个基本要素的缩写: 原子性(atomicity,或叫不可分割性),一致性(consistency),隔离性(isolation,又称独立性),持久性(dura ...
- SQL Server 2008对日期时间类型的改进
微软在备受多年的争议后,终于对日期时间数据类型开刀了,在新版的SQL Server 2008中一口气增加了4种新的日期时间数据类型,包括: Date:一个纯的日期数据类型. Time:一个纯的时间数据 ...
- js实现本地时间同步
HTML代码 <html> <head> <title>时间</title> <meta charset="utf-8"> ...