news 2026/6/10 17:02:52

从一道前端面试题,谈 JS 对象存储特点和运算符执行顺序

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从一道前端面试题,谈 JS 对象存储特点和运算符执行顺序

本文大纲

今天来看一道前端面试的代码输出题。

面试官提供了一段Javascript代码,要求给出这段代码运行后的输出结果。

constobj={a:0,};obj['1']=0;obj[++obj.a]=obj.a++;constvalues=Object.values(obj);obj[values[1]]=obj.a;console.log(obj);

先分析这道题前,先补充两个个前置知识点。

知识点一:对象的常规属性 (properties) 和排序属性 (elements)

先来看下面一段代码:

constobj={};obj['b']='b'obj[100]='100';obj[1]='1';obj['a']='a';obj[50]='50';obj['c']='c';for(constkeyinobj){console.log(`key:${key}value:${obj[key]}`)}/** * 打印结果如下: key: 1 value: 1 key: 50 value: 50 key: 100 value: 100 key: b value: b key: a value: a key: c value: c */

观察下打印的数据,很明显属性的设置顺序并不是打印的顺序,比如b属性是第一个设置的,打印结果却排在100后面,仔细分析他们的打印规律,可以得到如下特点:

  1. 数字类的属性不管设置的顺序先后,都会被优先打印,而且是按照从小到大的升序进行打印的。
  2. 字符类属性会按照设置的顺序进行打印,上面我们是按照bac的顺序进行设置的,打印顺序也是如此。

为什么会出现这样的结果呢?

这是因为 ECMAScript 规范中定义了数字属性应该按照索引值大小升序排列,字符串属性根据创建时的顺序升序排列。在V8中数字属性被称为elements,字符串属性被称为properties。之所以这样设置,主要是为了提升访问性能。elements对象中会按照顺序存放数字属性,类似于数组的存储,这样查询的效率当然就很高了。

知识点二:JavaScript 运算符的执行顺序

JavaScript中最常见运算符如下(运算顺序从高到低排列):

  • 对象属性访问,比如obj.aobj['a']
  • 递增/递减,比如a++(后置递增) 或++a(前置递增)。
  • 算术,比如a + 1
  • 比较,包括<(小于)、>(大于)、<=(小于等于)、>=(大于等于),比如a > 3
  • 相等,包括==粗略相等,===严格相等,!==粗略不等,!==严格不等,比如a == 1
  • 逻辑,也就是与或非,&(与)、|(或)、!(非),比如a && b
  • 三元,比如flag ? '1' : '0'
  • 赋值,比如a = 1

对于单个赋值语句LHS = RHS的求值,根据ECMAScript规范(ECMA-262, AssignmentExpression evaluation),对于LeftHandSideExpression = AssignmentExpression,其计算顺序如下:

  • 第一步,先得到一个引用(Reference),即“要写入的位置”,也就是Evaluate LeftHandSideExpression
  • 第二步,再计算右侧的值,Evaluate AssignmentExpression
  • 最后将第二步得到的值写入第一步的引用当中。

也就是说,对于LHS = RHS这样的赋值表达式,其计算顺序是左侧先求值(为了知道写到哪),右侧后求值(为了知道写什么),最后将右侧的值写入左侧。

📌 注意:这里说的“左侧求值”不是求它的值,而是求它的“位置”(比如属性名、变量名等)。例如对于obj[++obj.a],要确定属性名,就必须先执行++obj.a

写个简单例子:

constobj={geta(){console.log('获取 a 的值');return1;},getb(){console.log('获取 b 的值');return2;}}obj[++obj.a]=obj.b++;console.log('obj: ',obj);

我们前面说过,运算符顺序是对象属性访问 > 递增/递减 > 赋值,对于赋值运算符LHS = RHS,会先求出左侧LHS引用(Reference),再计算右侧RHS的值,最后将右侧的值赋值给左侧的引用。所以用这个逻辑来分析下这段代码的执行顺序:

  • 第一步,先取obj.a的值, 取到的值为1, 然后执行前置递增++obj.a,结果为2,然后程序就知道要往obj2属性上赋值了。
  • 第二步,然后再取obj.b的值,执行后置递增obj.b++,右侧计算的值为2
  • 最后把右侧计算的结果值2赋值给obj[2]属性。

逐行分析代码执行过程

了解了这两个知识点后,让我们来逐行解析下这段代码。

constobj={a:0,};obj['1']=0;obj[++obj.a]=obj.a++;constvalues=Object.values(obj);obj[values[1]]=obj.a;console.log(obj);
  1. 首先,我们定义了一个对象obj,它有一个属性a,值为0
constobj={a:0,};
  1. 接下来,我们给obj添加了一个属性1,值为0,此时对象中有两个属性,a1
obj['1']=0;

由于数字属性会排在前面,此时obj的值为:

{"1":0,"a":0,}
  1. 然后会执行obj[++obj.a] = obj.a++,前面我们分析过运算符的优先级,先执行左侧++obj.a得到1,然后执行右侧obj.a++, 由于是后置递增,所以右侧的值为1,执行赋值后,obj的值为:
{"1":1,"a":2,}
  1. 经过Object.values(obj)后,values的值为[1, 2]
  2. 执行obj[values[1]] = obj.a,转换后就是obj[2] = 2obj的值变为:
{"1":1,"2":2,"a":2,}

这就是最终的输出结果了。

小结

该题主要考察两个知识点:

  1. JavaScript对象中,属性的设置顺序并不一定是循环打印顺序,在V8中,数字类的属性在被称为elements(按从小到大排列存储),字符类属性被称为properties(按添加顺序存储)。
  2. JavaScript运算符的运算顺序是对象属性访问 > 递增/递减 > 赋值,对于赋值运算符LHS = RHS,会先求出左侧LHS引用(Reference),再计算右侧RHS的值,最后将右侧的值赋值给左侧的引用。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 15:36:16

计算机网络必看:信道的极限容量,408真题常考!

计算机网络必看&#xff1a;信道的极限容量&#xff0c;408真题常考&#xff01;在学习计算机网络时&#xff0c;你是否曾困惑&#xff1a;“为什么网速不能无限快&#xff1f;” “一个信道到底能传多快&#xff1f;”这些问题的答案&#xff0c;就藏在信道的极限容量这个核心…

作者头像 李华
网站建设 2026/6/10 11:46:17

MySQL----case的用法

在 MySQL 中&#xff0c;CASE 表达式是一个用于条件判断的功能&#xff0c;可以根据不同的条件返回不同的结果。CASE 表达式通常用于 SELECT 查询语句中&#xff0c;可以在 SQL 中灵活地进行条件判断和数据转换。CASE 有两种基本的语法形式&#xff1a; 简单 CASE 表达式&#…

作者头像 李华
网站建设 2026/6/10 11:45:13

MySQL 数据类型详解:TINYINT、INT 和 BIGINT

在设计数据库时&#xff0c;选择合适的数据类型对于系统性能和存储效率至关重要。MySQL 提供了多种整数类型来满足不同的存储需求&#xff0c;其中包括 TINYINT、INT 和 BIGINT。本文将详细介绍这三种整数类型的区别、应用场景和使用建议。 1. TINYINT TINYINT 是 MySQL 中存储…

作者头像 李华
网站建设 2026/6/10 10:59:26

基于python深度学习的面部表情识别系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了多年的设计程序开发&#xff0c;开发过上千套设计程序&#xff0c;没有什么华丽的语言&#xff0c;只有实…

作者头像 李华
网站建设 2026/6/10 10:59:14

【ITK手册006】itk::Point 深度解析与实用指南

【ITK手册006】itk::Point 深度解析与实用指南 0. 概述 在 ITK (Insight Segmentation and Registration Toolkit) 的几何框架中&#xff0c;itk::Point 是最基础的类之一。它用于表示 n 维欧几里得空间中的一个静态位置&#xff08;坐标&#xff09;。 与 itk::Vector&#xf…

作者头像 李华
网站建设 2026/6/10 10:53:46

论文写作隐藏技巧:7款AI神器5分钟生成3万字+真实参考文献揭秘

开头&#xff1a;90%的学生不知道的论文“黑科技”&#xff0c;导师私藏的学术加速密码 你是否经历过&#xff1a; 对着空白文档熬到凌晨3点&#xff0c;初稿还停留在“研究背景”&#xff1f;导师的修改意见像“天书”&#xff0c;改了3遍还是被打回&#xff1f;查重报告飘红…

作者头像 李华