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. iOS 转盘抽奖游戏(原生)

    转盘抽奖游戏在一般的app中都会有,应该算是一种吸引用户的一种手段.在项目中集成转盘抽奖游戏,大都采用h5的方式来实现,但是由于项目需求,需要在app中使用原生来实现转盘抽奖.实现原理也很简单,中间的 ...

  2. linux学习笔记6--命令mv

    mv命令是move的缩写,可以用来移动文件或者将文件改名(move (rename) files),是Linux系统下常用的命令,经常用来备份文件或者目录. mv命令用来对文件或目录重新命名,或者将文 ...

  3. FlashBuilder 4.6序列号破解

    1424-4827-8874-7387-0243-7331 1424-4938-3077-5736-3940-5640 具体步骤如下: 1.到Adobe官网下载FlashBuilder 4.6,有简体 ...

  4. python3颜色输出

    遇到一个项目,需求是在python3中,处理结果显示高亮加颜色,然后资料整理如下 ### 格式: \033[显示方式;前景色;背景色m 这里的格式是规定了m后面的输出字符颜色样式 说明: 前景色 背景 ...

  5. 在grub的rescue模式修复linux引导

    今天在windows 10系统收到系统更新通知,没看清楚就手贱点了马上更新.以为只是像那些普通更新一样重启一下更新就完了,万万没想到这个是覆盖更新,也就是说这是一个全新的系统更新而不是系统补丁.在安装 ...

  6. 动态添加js的方法

    var Skip={};//获取XMLHttpRequest对象(提供客户端同http服务器通讯的协议)Skip.getXmlHttpRequest=function (){ if ( window. ...

  7. 你是怎么理解java的泛型的?

    解答: 在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知 ...

  8. Android将指定的.class打包到mainDex中

    1️⃣ 我们分包的时候会遇到一个问题,因为加载和初始化的问题,如果某个类不在mainDex中,那么程序就会报错,java.lang.NoClassDefFoundError. 2️⃣ 在gradle中 ...

  9. HP proliant服务器从usb启动

    1,开机出现自检画面开始按F9进入设置,进入BIOS 选择standard boot order(rpl),把usb driver放在第一位,保存好 2,按F1开始启动. (注:我使用ubuntu14 ...

  10. QT软件初次使用中遇到的若干问题及思考

    1.QT窗口名称汉字设置问题? 答案:在MSVC中试用诸多方法,亲测都不行. 解决方案1:创建项目时,选择使用MSGW方案,用gcc进行编译,即可解决 2.QT中ui文件中组件不能再.cpp文件中显示 ...