cnblogs标题: JS连等赋值的坑

关于JS连等赋值有个经典的笔试题:

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

咋一看, 一脸懵逼, 这都什么玩意. 我一开始也是这个想法, 不过理解之后发现, 不是题目坑,

确实自己水平还不到位. 本文先介绍理解上述笔试题需要的知识点, 然后对该笔试题详细分析.

单个赋值表达式

形如A = B的表达式被称为赋值表达式, 其中A和B又分别可以是表达式, B可以是任意表达式,

而A必须是可以被赋值的表达式. 最关键的是我们要理解JS引擎是如何解析赋值表达式的:

  1. 先计算表达式A, 得到一个引用refA;
  2. 再计算表达式B, 得到一个值valueB;
  3. 将valueB赋给refA指向的位置;
  4. return valueB;

这4个步骤最核心的是规定了, 必须先计算A, 再计算B. 我们在文末分析笔试题就会看到.

多个连等解析

A1 = A2 = A3 = A4, 知道单个赋值表达式的解析逻辑, 多个连等赋值就很容易类推. 出现

多个连等, 我们完全可以给它分解成单个等号的形式. 比如上式可以分解成下面这样:

A1 = (A2 = A3 = A4), 左边的A1看成单个赋值表达式中的A, 右边整体看成B. 继续分解,

最终得出这样A1 = (A2 = (A3 = A4)). 因此这个连等的按步骤执行如下:

  1. 依次计算A1, A2, A3, 分别得到refA1, refA2, refA3;
  2. 计算A4得到valueA4, 把valueA4赋给A3;
  3. 把(A3 = A4)这个赋值表达式的返回值, 也就是value4赋给A2;
  4. 把(A2 = (A3 = A4))这个赋值表达式的返回值, 也就是value4赋给A1;

大家不要蒙圈, 就在脑中这样想, 先计算左后计算右. 左边就单个A1, OK直接计算. 来到右

边发现没法直接计算, 那么就把右边再分成左右, 按照这种思路循环递推就行.

和学二叉树时候的思路, 简直如出一辙.

再看笔试题

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

你可能会发现, 现在貌似还是不理解上面的代码到底发生了什么, 说明对JS中引用赋值, 理解还不

够透彻.

上面总共5行代码, 按顺序编号1-5.

  1. 首先执行前2行代码, 我们脑中大致有这样的图. a --> [ {n: 1} ] <--b, 说这是图太勉强, 大家

    将就看_. 这个图中间的[]表示这是个盒子, 盒子里面装有{n: 1}这个对象,ab都指向这个

    对象.
  2. 接下来, 到了全文最关键的时刻. 按照我们前面的分析, 第3行代码先执行a.x, 这时候我们上面的

    的图已经发生变化了, 变成这样a --> [ {n: 1, x: } ] <--b, 我们的x同学已经准备好了, 等着

    别人给它赋值呢.
  3. 再接着执行a, 我们的图没发生变化.
  4. 在接着执行{n: 2}, 大家注意这可是我们全新召唤出来的盒子, 盒子里面装有数据{n: 2}. 该

    盒子和前面的{n: 1}盒子没有任何关系(到目前为止).
  5. 为了方面我们就把第一次出现的盒子叫做盒子1, 第2次出现的的字叫做盒子2. 现在我们把盒子2赋给

    a, 我们的脑中将出现2个图. 图1[ {n: 1, x: } ] <--b, 图2a --> [ {n: 2} ]. 也就是说

    a已经指向了盒子2, 而b仍旧指向盒子1.
  6. 我们把a = {n: 2}这个表达式的返回值{n: 2}赋给x同学, 对就是x, x一直在等着呢, 现在

    没有a什么事了. 最终我们的图变成了这样, 图1[ {n: 1, x: {n: 2} } ] <--b,

    图2a --> [ {n: 2} ].

我们上述6个步骤图的变化单门拿出来:

a --> [ {n: 1} ] <--b

a --> [ {n: 1, x: } ] <--b

[ {n: 1, x: } ] <-- b
a --> [ {n: 2} ] // 最终图
[ {n: 1, x: {n: 2} } ] <--b
a --> [ {n: 2} ]

现在让我们输出什么, 我们就能输出什么.

console.log(a.x);   // a现在指向的盒子2, 盒子2里没有x, 输出undefined
console.log(b.x.n); // 2

参考链接

https://segmentfault.com/a/1190000004224719#articleHeader0

JS连等赋值的坑的更多相关文章

  1. (网页)Angular.js 中 copy 赋值与 = 赋值 区别

    转自st.gg Angular.js 中 copy 赋值与 = 赋值 区别 为什么用 $scope.user = $scope.master; $scope.master 会跟着 $scope.use ...

  2. 关于JS变量提升的一些坑

    function log(str) { // 本篇文章所有的打印都将调用此方法 console.log(str); } 函数声明和变量声明总是会被解释器悄悄地被“提升”到方法体的最顶部 变量声明.命名 ...

  3. 蛮考验基础的JS笔试题(有坑小心!)

    1.  考察this var length = 10 function fn(){ alert(this.length) } var obj = { length: 5, method: functi ...

  4. JS 的引用赋值与传值赋值

    这个问题说大不大说小不小,如果你有幸踩了这个坑,一定会找这篇文章,哈哈~ 现说一下JS数字的类型:基本类型和引用类型 先看下下面两个栗子: var a = 30; var b = a; a = 20; ...

  5. js连等赋值

    引用:http://www.iteye.com/topic/785445 https://segmentfault.com/q/1010000002637728 这是一个问题 var a = {n:1 ...

  6. js的this上下文的坑

    很明显,this这个坑,在多层嵌套的时候还是一样被废,不管是call, apply还是bind. 例如: var fun = function() { this.name = 'test'; var ...

  7. 用js刷题的一些坑

    leecode可以用js刷题了,我大js越来越被认可了是吧.但是刷题中会因为忽略js的一些特性掉入坑里.我这里总结一下我掉过的坑. 坑1:js中数组对象是引用对象 js中除了object还有数组对象也 ...

  8. Js的引用赋值与传值赋值

    要说js的赋值方式时首先要说明js的数值类型:基本类型和引用类型. 1.基本类型 基本的数据类型有:undefined,boolean,number,string,null. 基本类型存放在栈区,访问 ...

  9. js关键字与保留字的坑。

    在写一个算法,迷宫出口的算法,作为一个有追求的前端,首先在解决算法的问题之前要把迷宫的图做的漂漂亮亮的才对得住自己的审美,所以我花了一个钟的时间去写这个地图. 不过这次我们说的并不是迷宫的解法,也不是 ...

随机推荐

  1. 15.3.14 DP练习2

    拦截导弹 题目 某国为了防御敌国的导弹突击,发展出一种导弹拦截系统. 可是这样的导弹拦截系统有一个缺陷:尽管它的第一发炮弹可以到达随意的高度.可是以后每一发炮弹都不能高于前一发的高度. 某天,雷达捕捉 ...

  2. Echarts中线状图的X轴坐标标签倾斜样式

    在echarts中应用线状图时可以展现很多的数据,而当数据量过多的时候,X轴的坐标就会显示不全,因为整个图形的宽度是一定的,X轴的全长是一定的 http://www.cnblogs.com/phpgc ...

  3. 清空oracle数据库

    在开发过程中,可能经常需要重新初始化数据库,在初始化之前,我们肯定希望不再有以前的老表.存储过程等用户对象,用下面的教本就可以做到这一点: BEGIN FOR rec IN (SELECT objec ...

  4. OkHttp+Stetho+Chrome调试android网络部分(原创)

    android网络调试一直是一个比较麻烦的部分,因为在不同序列的请求中,返回的数据会有不同的变化,如果能像web开发一样使用调试功能查看页面的访问数据该是多么美好的事情! 很幸运的是,现在Androi ...

  5. nginx 为什么要反向代理 影藏后端 高效连接(给nginx,他自己返回) 端口冲突解决 多个服务

    nginx 为什么要反向代理  影藏后端   高效连接(给nginx,他自己返回)  端口冲突解决  多个服务 单机使用反向代理可以根据不同url匹配到不同站点   rsync 的工作原理和应用实例 ...

  6. 编写可维护的JavaScript----笔记(一)

    1.缩进层级 建议使用4个空格为一个缩进层级,避免使用制表符进行缩进,可以通过配置文本编辑器来改变 缩进层级表示的内容. 2.语句末尾 有赖于分析器的自动分号插入机制(ASI),JavaScript可 ...

  7. easyui.dialog.js

    (function ($) { var $parent = parent.$; //获取弹出窗口数据集合 function getDialogs() { var dialogs = $parent(& ...

  8. 第二百四十三节,Bootstrap模态框插件

    Bootstrap模态框插件 学习要点: 1.基本使用 2.用法说明 本节课我们主要学习一下 Bootstrap 中的模态框插件,这是一款交互式网站非常常见的 弹窗功能插件. 一.基本使用 使用模态框 ...

  9. 第二百三十节,jQuery EasyUI,后台管理界面---后台管理

    jQuery EasyUI,后台管理界面---后台管理 一,admin.php,后台管理界面 <?php session_start(); if (!isset($_SESSION['admin ...

  10. MFC中CString.Format的用法

    http://www.cnblogs.com/kongtiao/archive/2012/06/13/2548033.html 在MFC程序中,使用CString来处理字符串是一个很不错的选择.CSt ...