1310 字
7 分钟

属性名的本质,伪数组存在的原因

欢迎来到我的博客!#

使用 Markdown 格式编写。

今天学到了什么#

  • 属性名的本质
  • 伪数组存在的原因

属性名的本质#

这是一个非常好的问题!你的观察很仔细。

简单来说:在 JavaScript 中,对象的属性名(键)其实本质上都是字符串,但写的时候可以“偷懒”省略引号。

下面是详细的解释:

  1. 对象的属性名不仅仅是那串字符 在定义对象 msg 时:

    const msg = {
    "code": 200, // 写了引号
    "data": [...] // 写了引号
    }

    和下面这种写法,在 JavaScript 引擎看来是完全一样的:

    const msg = {
    code: 200, // 没写引号(只要符合变量命名规则,就可以省略引号)
    data: [...] // 没写引号
    }

    虽然在 JSON 格式(通常是后台传回来的数据格式)中严格要求属性名必须加双引号,但在 JavaScript 代码里操作这些对象时,属性名 data"data" 指向的是同一个东西。

  2. 解构赋值的匹配规则 当你写:

    const { data } = msg

    JavaScript 的意思是:“请去 msg 对象里找一个叫名为 data 的属性,并把它赋值给一个叫 data 的变量。”

    它不需要你去匹配**“定义时的写法”(是否有引号),而是匹配“属性的名字”**。因为在内存里,这个属性的名字就是 data

总结

  • 定义时"data":data: 是一样的(只要通过了语法检查)。
  • 解构时:只要写属性名 data 就能找到它,不需要加引号。

如果非要加引号会怎样? 如果你在解构时强行加引号,语法会变复杂,通常我们只有在属性名包含特殊字符(比如 data-list 这种带横杠的)时,才被迫需要用引号别名的方式来解构,例如 const { "data-list": list } = obj,但标准变量名直接写即可。

伪数组存在的原因#

伪数组(Pseudo-array / Array-like object)的存在主要是出于 性能优化特定功能需求 以及 历史遗留 的原因。

简单来说,伪数组就是一个拥有 length 属性和数值索引(0, 1, 2…)的对象,但它没有数组原型链上的方法(如 push, pop, map, filter 等)。

以下是它存在的几个主要原因:

1. 性能与内存优化 (轻量级)#

真正的数组(Array)在 JavaScript 引擎中是非常复杂的对象,它背负了整套原型链方法(数十种方法)和特殊的引擎优化机制。

  • DOM 操作场景:当你需要获取成千上万个 DOM 元素(如 document.querySelectorAllarguments)时,创建一个简单的“带索引的对象”比创建一个完整的“数组对象”要快得多,占用的内存也更少。
  • 浏览器设计者认为,绝大多数时候你只用来遍历(for循环),不需要对这些元素列表进行 pop(弹出)或 splice(截接)等复杂操作。

2. Live Collection (动态集合) 特性#

某些伪数组(如 HTMLCollection,通过 getElementsByClassName 获取)具有 “实时性” (Live) 的特点。

  • 数组是静态的const arr = [div1, div2],如果你删除了页面上的 div1,数组里的 div1 引用依然存在,不会自动消失。
  • 伪数组可以是动态的HTMLCollection 会随着 DOM 树的改变自动更新。如果页面删除了一个元素,伪数组的 length 会自动减 1。普通的数组很难高效地实现这种“自动同步”的魔法。

3. 防止误操作 (安全性)#

DOM 元素集合通常代表页面上的现状。

  • 如果你在一个 DOM 集合上调用 pop(),这意味着什么?是把元素从集合里移除,还是把元素从页面上删除?这会有歧义。
  • 通过不提供修改数组的方法(如 push, shift),浏览器API 限制了开发者只能“读取”列表,而不能随意修改列表结构,从而避免了很多潜在的 Bug。

4. 历史遗留原因#

在 JavaScript 早期(ES3/ES5 时代),语言设计比较简单。当时 arguments 对象也是用来访问函数参数的唯一方式,为了效率并没有把它设计成真数组。随着时间推移,为了保持 Web 兼容性,这些设计就保留了下来。


总结

特性真数组 (Array)伪数组 (Array-like)
主要用途存储数据,进行各种数据操作存储 DOM 节点引用、函数参数等临时列表
方法支持forEach, map, filter, reduce通常只有 length 和索引访问 (新版 NodeList 支持 forEach)
内存开销较大较小
动态更新否 (静态快照)部分是 (如 collection 会随 DOM 变化)

转换方法(即你当前文件正在学习的内容): 由于现代开发中我们经常需要用到 mapfilter,所以 ES6 提供了 Array.from() 或者展开运算符 [...] 来方便地把它们转成真数组:

// 你的代码中的例子
const lis = document.querySelectorAll('ul li') // 这是一个 NodeList (伪数组)
// 转换
const realArray = Array.from(lis)
// 或者
const realArray2 = [...lis]
// 现在可以愉快地使用了
realArray.map(item => console.log(item))

赞助支持

如果这篇文章对你有帮助,欢迎赞助支持!

赞助
属性名的本质,伪数组存在的原因
https://firefly.cuteleaf.cn/posts/study-everyday/2026-02-23今日学习-属性名的本质/
作者
LJC
发布于
2026-02-23
许可协议
CC BY-NC-SA 4.0
最后更新于 2026-02-23,距今已过 25 天

部分内容可能已过时

目录