一、引子

最近在看别人的博客时无意中看到一个这样的问题

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

这是一个典型的连等赋值问题,是不是发现打印的结果跟自己预料的不太一样,就算一样你能具体讲出内部的执行机制吗?

二、直观理解

咋一看这个表达式,我会本能地把它拆解为这样

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

所以根据这个理解得出的打印结果是

console.log(a.x);  //{n: 2}

显然结果是不对的,那问题出在了哪里呢?要想从原理上解释这个问题,还得首先理解以下几个知识点

三、需要理解的知识点

  • 内存的的运行机制
  • JS引擎的解析过程,从左往右
  • 连等赋值的执行方向,从右往左

放在这个例子中对应的理解就是:

  • a、b这些变量名存储的只是一串指向具体对象的指针,这些指针占用的空间是非常小的,而{n: 1}这些对象才是实实在在存在内存中的值
  • JS引擎在执行到a.x = a = {n:2}这句时,并不是直接的从右往左的执行过程。而是计算机会先从左往右解析各个变量名,转换成变量值(计算机只会记变量值,人的话记变量名)。再从右往左执行赋值。
  • 也就是在这个表达式中第一个a和第二个a指向的都是{n: 1};
    a.x = a = {n:2}
  • 解析完成后,从右往左执行赋值,第二个等号赋值时,a重定向到了{n: 2},第一个等号赋值时,实际上是{n:1}.x={n, 2};

    而这个时候指向{a:1, x:{n:2}}这个值的只有b了
  • 所以a.x的值就变为了undefined,因为a已经重定向赋值为{n:2}了,而b就指向了复合之后的对象

四、理解中的误区及思考

我最开始查了连等赋值的相关文章时,对于以上这些原理的理解是没什么问题的,关键是在理解最后那个赋值过程时,我有过一种理解

a = {n:2};
a.x={n:2};
// 所以此时a= {n:2, x:{n:2}}

产生这种理解的原因是觉得对a的赋值有个先后顺序,但事实上好像是不存在的。我对上面那种从解析赋值角度去理解的核心就是在连等赋值执行过程中,总共分为两步,一步是变量名解析,一步是赋值,然后根据赋值之后的值去看相应的变量名与变量之间的对应关系。

五、参考文档

探究JS中的连等赋值问题的更多相关文章

  1. 【转】千万不要在JS中使用连等赋值操作

    原文链接 千万不要在JS中使用连等赋值操作   目录 前言 赋值顺序? 连续赋值能拆开写么? 后记 前言 文章标题这句话原本是在国外某JavaScript规范里看到的,当时并没有引起足够的重视,直到最 ...

  2. 深入探究js中的隐式变量声明

    前两天遇到的问题,经过很多网友的深刻讨论,终于有一个相对可以解释的通的逻辑了,然后我仔细研究了一下相关的点,顺带研究了一下js中的隐式变量. 以下文章中提到的隐式变量都是指没有用var,let,con ...

  3. 千万不要在JS中使用连等赋值操作

    前言 文章标题这句话原本是在国外某JavaScript规范里看到的,当时并没有引起足够的重视,直到最近一次出现了bug发现JS里的连等赋值操作的特色(坑). 网上搜索一番发现一个非常好的连等赋值的(来 ...

  4. 深入探究js中无所不在的this

    黄金守则: this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window而当函数被作为某个对象的方法调用时, this等于那个对象. 下面是一些相关实践: --------- ...

  5. 探究JS中对象的深拷贝和浅拷贝

    深拷贝和浅拷贝的区别 在讲深拷贝和浅拷贝的区别之前,回想一下我们平时拷贝一个对象时是怎么操作的?是不是像这样? var testObj1 = {a: 1, b:2}, testObj2=testObj ...

  6. JS中数组初始化以及赋值

    .指定长度,然后初始化 ); ;index < ;index++){ vArray[index] = index; } 2.不指定长度,然后初始化 var vArray = new Array( ...

  7. js 中的基本类型和引用类型的区别

    js中的基本类型赋值之后,只有值相等的时候,二者才会相等,例如 var  a='123'; var b=a; console.log(a===b); 返回的是true ,说明他们是相等的, 此时改变a ...

  8. js中的offsetLeft和style.left

    (1)style.left是带单位"px"的,而offsetLeft没有单位,另外,style.left必须是内联样式,或者在JS中通过style.left赋值,否则取得的将为空字 ...

  9. 二、js中基础知识

    该篇文章主要是强化一下自己javaScript的基础,让写代码变得更轻松些.基础好的请忽略.    JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解 ...

随机推荐

  1. Linux系统——本地定制化yum仓库部署

    1)开启yum仓库配置文件 /etc/yum.conf的keepcache功能 (开启一个新的虚拟机) 将keepcache=0改为1,修改配置文件后重新清空缓存(1默认下载的安装包不删除,才可以实现 ...

  2. Redis持久化及复制

    一.持久化的两种方式 1.RDB: RDB是在指定时间间隔内生成数据集的时间点快照(point-in-time snapshot)持久化,它是记录一段时间内的操作,一段时间内操作超过多少次就持久化.默 ...

  3. cocos2dx 3.x HttpRequest GET获取数据

    .h文件 #include "network/HttpClient.h" //包含头文件 // GET 函数 void createGetHttp(); void getHttp_ ...

  4. 谷歌技术"三宝"之谷歌文件系统(转)

    原文地址:http://blog.csdn.net/opennaive/article/details/7483523 题记:初学分布式文件系统,写篇博客加深点印象.GFS的特点是使用一堆廉价的商用计 ...

  5. 计算mysql 数据库 表大小 服务器传输 小写表明转成大写

    //数据库表存储大小 select table_schema,table_name,table_rows,concat(round(data_length/1024/1024/1024,2),'GB' ...

  6. Django学习笔记之URL标签的使用

    期初用django 开发应用的时候,完全是在urls.py 中硬编码配置地址,在views.py中HttpResponseRedirect()也是硬编码转向地址,当然在template 中也是一样了, ...

  7. web.py url传参及获取

    第一种:直接获取: import web urls = ( '/(.*)','index' #URL后面必须加(.*) ) class index: def GET(self,name): print ...

  8. ::before ::after CSS3中的伪类和伪元素

    ::before和::after伪元素的用法 一.介绍 css3为了区分伪类和伪元素,伪元素采用双冒号写法. 常见伪类——:hover,:link,:active,:target,:not(),:fo ...

  9. 如何用纯 CSS 创作单元素点阵 loader

    效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览.https://codepen.io/comehope/pen/YvBvBr 可交互视频 此 ...

  10. RocEDU.阅读.写作《苏菲的世界》书摘

    我们在成长的过程当中,似乎失去了对这世界的好奇心.也正因此,我们丧失了某种极为重要的能力(这也是一种哲学家们想要使人们恢复的能力).因为,在我们内心的某处,有某个声音告诉我们:生命是一种很庞大的.神秘 ...