拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

使用 Object.keys 统计 JavaScript 对象属性数量:count(obj) 实战任务解析

使用 Object.keys 统计 JavaScript 对象属性数量:count(obj) 实战任务解析
  • 文档/教程
  • 前端

【免费下载链接】en.javascript.info

Modern JavaScript Tutorial

项目地址:https://gitcode.com/gh_mirrors/en/en.javascript.info
点击查看免费下载

本篇技术指南以 Modern JavaScript Tutorial(本仓库1-js教程体系)中的实战任务为核心,讲解如何编写一个简洁的count(obj)函数来统计普通对象的属性数量。文章将完整还原任务要求、标准解法与配套测试用例,并深入剖析Object.keys/Object.values/Object.entries三兄弟的底层行为(包括它们与for..in一样会忽略 Symbol 键这一关键特性),帮助读者理解"为什么Object.keys(obj).length是最短且正确的答案"。

任务背景:它属于哪一章

本任务是 JavaScript 基础部分"数据类型(Data Types)"章节中 Object.keys, values, entries 一节的配套练习。该章节在讲完Map、Set、Array的迭代方法之后,专门介绍普通对象的三个静态方法:

  • Object.keys(obj)—— 返回由对象所有键组成的数组;
  • Object.values(obj)—— 返回由对象所有值组成的数组;
  • Object.entries(obj)—— 返回[key, value]键值对数组。

与Map的map.keys()这种实例方法语法不同,普通对象必须用静态调用形式Object.keys(obj),且返回的是"真正"的数组(而非可迭代对象)。关于二者的差异,章节中给出了清晰的对照表:

MapObject
调用语法map.keys()Object.keys(obj),而不是obj.keys()
返回值可迭代对象"真正的"数组

任务原文:count(obj)

任务文件位于 02-count-properties/task.md,要求如下:

编写一个函数count(obj),返回对象中属性的数量:

let user = { name: 'John', age: 30 }; alert( count(user) ); // 2

同时附带两条要求:

  1. 让代码尽可能短;
  2. 忽略 Symbol 类型的属性,只统计"常规"属性(P.S. 提示语)。

这是一个重要性标记为importance: 5的核心练习,考察的正是Object.keys的使用与对"Symbol 键被忽略"这一语义的掌握。

标准解法:一行代码

仓库中配套的标准解法位于 02-count-properties/_js.view/solution.js,完整代码如下:

function count(obj) { return Object.keys(obj).length; }

这个解法之所以是"最短且正确"的,原理链条如下:

  1. Object.keys(obj)返回一个包含对象自身可枚举字符串属性名的数组;
  2. 由于Object.keys与for..in一样会忽略以Symbol(...)为键的属性(详见章节中的 warn 提示),因此统计结果天然满足"忽略 Symbol 属性"的要求;
  3. 对数组取.length即为属性数量。

需要说明的是,Object.keys只统计自身的可枚举字符串属性,不含原型链上的继承属性。对本题这样的普通字面量对象而言,这恰好就是我们想要的行为。

测试用例:三种边界验证

仓库为每个任务都提供了配套的 Mocha 测试,本任务的测试位于 02-count-properties/_js.view/test.js,共覆盖三个典型场景:

describe("count", function() { it("counts the number of properties", function() { assert.equal( count({a: 1, b: 2}), 2 ); }); it("returns 0 for an empty object", function() { assert.equal( count({}), 0 ); }); it("ignores symbolic properties", function() { assert.equal( count({ [Symbol('id')]: 1 }), 0 ); }); });

逐条解读:

  • 常规属性计数:{a: 1, b: 2}有两个字符串键,结果为2;
  • 空对象边界:{}没有任何属性,Object.keys({}).length为0,这保证函数对空对象不报错;
  • Symbol 键忽略:{ [Symbol('id')]: 1 }中唯一属性是 Symbol 键,结果为0,验证了任务 P.S. 中的核心要求。

从源码结构看,_js.view目录是任务的"可运行视图",其中solution.js为被测试的实现、test.js为断言脚本,二者共同构成了读者可以在浏览器中直接运行的练习环境。

深入理解:为什么 Symbol 键被忽略

任务 P.S. 特意强调"忽略 symbolic properties",这是本练习的隐藏考点。在 article.md 的 warn 提示中,教程明确指出:

就像for..in循环一样,Object.keys/Object.values/Object.entries会忽略使用Symbol(...)作为键的属性。通常这很方便。但如果我们也需要 Symbol 键,那么有一个单独的方法Object.getOwnPropertySymbols(obj)返回只包含 Symbol 键的数组;此外还有Reflect.ownKeys(obj)可以返回所有键。

因此在实际开发中,针对"统计属性数量"的需求要按场景选择:

需求场景推荐方法返回值示例
只统计常规字符串属性Object.keys(obj).length字符串键的个数
只统计 Symbol 属性Object.getOwnPropertySymbols(obj).lengthSymbol 键的个数
统计全部自身属性(含 Symbol 键)Reflect.ownKeys(obj).length字符串键 + Symbol 键的总数

延伸练习:Object.values 与求和

同一个章节还包含一个姊妹任务 01-sum-salaries:用Object.values和for..of循环求对象中所有薪水之和,空对象返回0。其标准解法在 01-sum-salaries/solution.md:

function sumSalaries(salaries) { let sum = 0; for (let salary of Object.values(salaries)) { sum += salary; } return sum; // 650 }

教程还给出一种更精简的替代写法——Object.values配合数组的reduce方法:

function sumSalaries(salaries) { return Object.values(salaries).reduce((a, b) => a + b, 0); // 650 }

这两个任务合在一起,恰好演示了Object.keys与Object.values的典型组合用法:前者用于获取结构信息(键的个数),后者用于遍历值做聚合计算。

进阶技巧:entries 与 fromEntries 组合变换

章节中Object.entries的一个重要用途是配合Object.fromEntries对对象做"数组化变换"。例如把价格对象中的所有价格翻倍:

let prices = { banana: 1, orange: 2, meat: 4, }; let doublePrices = Object.fromEntries( Object.entries(prices).map(entry => [entry[0], entry[1] * 2]) ); alert(doublePrices.meat); // 8

这个三步走的模式(Object.entries取出键值对数组 → 用数组方法map/filter变换 →Object.fromEntries还原为对象)弥补了普通对象没有map、filter等数组方法的短板。熟悉它之后,就能像处理数组一样对对象做任意链式变换,这也是本练习所在章节的进阶价值所在。

小结

  • count(obj)的标准答案是一行代码:Object.keys(obj).length;
  • Object.keys只返回自身可枚举的字符串键,天然忽略 Symbol 键,正好满足任务 P.S. 的要求;
  • 仓库配套测试(test.js)覆盖常规计数、空对象、Symbol 忽略三种边界,可用于验证实现的正确性;
  • 如需统计 Symbol 键,可改用Object.getOwnPropertySymbols;如需统计全部键,可改用Reflect.ownKeys;
  • 同章节的Object.values/Object.entries分别擅长聚合求值与"数组化变换",配合Object.fromEntries可完成强大的对象处理链。
  • 文档/教程
  • 前端

【免费下载链接】en.javascript.info

Modern JavaScript Tutorial

项目地址:https://gitcode.com/gh_mirrors/en/en.javascript.info
点击查看免费下载

相关推荐

上一篇:G-helper项目中的风扇控制与性能优化技术解析
下一篇:解决LazyVim缩进显示冲突:mini.indentscope与indent-blankline协同配置指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

返回列表