一文详解令人抓狂的JS赋值顺序

 更新时间:2025年08月25日 11:34:56   作者:代码里的小猫咪  
在JavaScript编程语言中,变量赋值是基础且核心的概念,正确理解和运用变量赋值不仅关系到代码的准确性,还影响着代码的性能和可维护性,这篇文章主要介绍了JS赋值顺序的相关资料,需要的朋友可以参考下

前言

你可能以为自己已经非常熟悉 JavaScript 的赋值操作了,但这一行代码:

var a = { n: 1 };
var b = a;
a.x = a = { n: 2 };

却让无数开发者陷入沉思:到底是先给 a.x 赋值,还是先给 a 重新赋值?为什么 console.log(b.x) 是一个对象,而 a.x 却是 undefined?这不是语法问题,而是 JavaScript 底层执行机制的奇妙。

下面就简单讲述一下。

JavaScript 赋值操作基础

运算符优先级与结合性

赋值运算符(=、+=、-=) 在 JavaScript 中是 右结合(right-to-left)的。这意味着表达式 a = b = c 会先计算右侧的 b = c,再把结果赋给 a。

运算符优先级结合性
=3右到左
+, -13左到右

.

20左到右

左值(L-value)与右值(R-value)

  •  左值:表达式的“赋值目标”,例如变量、对象属性、数组元素。
  • 右值:表达式的“计算结果”,例如字面量、函数返回值、其他表达式。

赋值时,JS 引擎要分别评估左值(确定要写到哪里)和评估右值(计算要写什么),然后才执行写入。

连续赋值语义

为什么 a = b = c 能连续写?

因为在 JS 中,赋值表达式本身会返回被赋的值,所以可以写成链式:

// 步骤拆解:
b = c        // 返回 c
a = (b = c)  // 再把 c 赋给 a

 赋值表达式的返回值

  • 表达式 x = y 的求值结果就是“被赋的值 y”。
  • 因此 a = b = 5 相当于 a = 5; b = 5;,且整个表达式的值为 5。
a = b = 5;
console.log(a, b, (a = b = 5)); // 5 5 5

ECMAScript 规范视角

如何评估赋值表达式

根据 ECMAScript® Language Specification(ECMA-262):

  1. 评估 AssignmentExpression:先识别运算符右侧的“AssignmentExpression”
  2. 评估左值:调用 GetValue 获取右侧的值
  3. 分辨目标:调用 PutValue 将值写入左值目标
  4. 返回值:整个表达式的值为所写入的值

步骤拆解

Function EvaluateAssignmentExpression(expr):
  If expr is “LeftHandSide = RightHandSide” then:
    // 1. 先评估右侧,得到一个值 R
    R = Evaluate(RightHandSide)
    // 2. 再评估左侧,得到一个引用 L
    L = ResolveReference(LeftHandSide)
    // 3. 将 R 写入 L
    PutValue(L, R)
    // 4. 返回 R 作为整个表达式的值
    return R

常见示例

1、简单链式赋值

let x, y, z;
x = y = z = 100;
console.log(x, y, z); // 100 100 100

执行顺序:

  1. z = 100  → 返回 100
  2. y = (z = 100) → 返回 100
  3. x = (y = (z = 100)) → 返回 100

2、对象属性与赋值顺序

let obj = { a: 1 };
obj.b = obj.a = 2;
console.log(obj); // { a: 2, b: 2 }

执行顺序:

  1.  先计算 obj.a = 2,写入 a,返回 2。
  2. 再执行 obj.b = <返回值 2>。

重点示例分析

var a = { n: 1 };
var b = a;
a.x = a = { n: 2 };

console.log(a.x);
console.log(b.x);

详解解析:

var a = { n: 1 };  // [Obj1]
var b = a;         // b ➔ [Obj1]
a.x = a = { n: 2 };  
  1. 解析左侧目标(Capture LHS)
    1. 引擎先看到整个赋值表达式 a.x = …,此时 a 仍指向最初的对象 [Obj1]。
    2. “目标位置”锁定为:对象 [Obj1] 的属性 x。
  2. 执行右侧赋值(Evaluate RHS)
    1. 新建一个对象字面量 { n:2 },记为 [Obj2]。
    2. 把 [Obj2] 赋给变量 a,此刻 a 从指向 [Obj1] 变为指向 [Obj2]。
    3. 赋值表达式 a = [Obj2] 的返回值是这个新对象 [Obj2]。
  3. 写入属性(Perform original “.x = …”)
    1. 虽然此时 a 已经指向 [Obj2],但左侧“目标”早已捕获,仍是 [Obj1].x 这个位置。
    2. 因此,将右侧返回的 [Obj2] 写入到原始对象 [Obj1] 的 x 属性上:Obj1.x = Obj2。
  4. 查看最终结果
    1. a 指向 [Obj2],所以 a.x 查的是 [Obj2].x ——该对象上没有 x 属性,结果 undefined。
    2. b 依旧指向最初的 [Obj1],它的 x 属性被写入了 [Obj2],所以 console.log(b.x) 输出 { n: 2 }。

关键点:

  • 左侧目标先捕获:赋值表达式开始时就确定属性写入位置,不受后续变量指向变化影响。
    • 左侧 a.x 在赋值之前就要解析“引用”,此时 a 仍指向旧对象;
    • 右侧 a = tmp 改变了 a 引用,但不会影响已经捕获的“属性写入位置”。
  • 赋值表达式返回值:a = {n:2} 返回新的对象引用,用于后续“属性赋值”。
  • 顺序原则:先捕获 LHS,再执行 RHS 并返回值,最后将返回值写入先前捕获的 LHS。

这样,一眼就能看清变量指向与属性写入的“先后关系”,避免踩坑。

总结

到此这篇关于JS赋值顺序的文章就介绍到这了,更多相关JS赋值顺序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JS限制文本框只能输入数字和字母方法

    JS限制文本框只能输入数字和字母方法

    这篇文章主要介绍了JS限制文本框只能输入数字和字母方法,本文给出了限制只能输入数字、限制只能输入字母、限制只能输入数字和字母3种脚本,需要的朋友可以参考下
    2015-02-02
  • Add a Table to a Word Document

    Add a Table to a Word Document

    Add a Table to a Word Document...
    2007-06-06
  • javascript 自定义常用方法

    javascript 自定义常用方法

    在实际的js开发过程中,我们常常会有相似或相同的需求。这时候如果没有很好的封装(通用功能),代码的重复将不可避免。
    2009-08-08
  • 万字详解JavaScript手写一个Promise

    万字详解JavaScript手写一个Promise

    这篇文章主要介绍了万字详解JavaScript手写一个Promise,Promise就是一个类,在执行这个类的时候,需要传递一个执行器(回调函数)进去,执行器会立即执行
    2022-07-07
  • 微信小程序web-view环境下H5跳转小程序页面方法实例代码

    微信小程序web-view环境下H5跳转小程序页面方法实例代码

    微信小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验,下面这篇文章主要给大家介绍了关于微信小程序web-view环境下H5跳转小程序页面方法的相关资料,需要的朋友可以参考下
    2022-08-08
  • JS+HTML实现经典游戏吃豆人

    JS+HTML实现经典游戏吃豆人

    吃豆游戏可以说是我们80,90后共同的回忆录,小时候常常在学习机上玩,所以也就有了强烈的欲望去写。所以本文将利用JS+HTML实现这一经典游戏,需要的可以参考一下
    2022-04-04
  • 基于bootstrap按钮式下拉菜单组件的搜索建议插件

    基于bootstrap按钮式下拉菜单组件的搜索建议插件

    这篇文章主要为大家详细介绍了基于bootstrap按钮式下拉菜单组件的搜索建议插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • 一文详解前端进阶之IntersectionObserver

    一文详解前端进阶之IntersectionObserver

    这篇文章主要为大家介绍了前端进阶之IntersectionObserver示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • Bootstrap导航简单实现代码

    Bootstrap导航简单实现代码

    这篇文章主要介绍了Bootstrap导航的简单实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • JavaScript模板字符串用法实例

    JavaScript模板字符串用法实例

    在ES6之前我们都使用单引号或者双引号来包裹字符串,当我们想要在字符串中加入变量时,不能直接写在字符串里,而是需要通过字符串拼接的方式来往字符串中加入变量,这篇文章主要给大家介绍了关于JavaScript模板字符串用法的相关资料,需要的朋友可以参考下
    2022-11-11

最新评论