所有分类
  • 所有分类
  • 游戏源码
  • 网站源码
  • 单机游戏
  • 游戏素材
  • 搭建教程
  • 精品工具

JavaScript怎么遍历对象?常用方法汇总+实战示例,一看就会

JavaScript怎么遍历对象?常用方法汇总+实战示例,一看就会 一

文章目录CloseOpen

这篇文章就把JavaScript对象遍历的常用方法全汇总了:从最基础的for...in(但要注意过滤继承属性),到更灵活的Object.keys()(只拿键名)、Object.values()(只取值),再到能同时抓键值对的Object.entries()配合for...of循环,每个方法都讲清适用场景+实战示例——比如用Object.entries()快速渲染一个对象的键值对列表,用for...in遍历带原型链的对象要加hasOwnProperty判断,甚至帮你避坑“遍历顺序不固定”“非枚举属性看不到”的问题。

不用再翻文档查语法细节,跟着例子走一遍,不管是简单对象还是复杂结构,你都能快速选对遍历方法,真正做到“一看就会,一用就对”,把对象遍历的活儿干得又快又稳。

做前端开发这几年,我最常被问的问题之一就是“JavaScript对象怎么遍历啊?”去年帮朋友做电商后台的订单详情页时,我就踩过一个大坑——当时要把订单对象的“商品名称”“数量”“单价”“总金额”这些字段展示出来,我想都没想就用了for...in循环,结果页面上多出来一堆奇怪的“__proto__”里的方法名,比如“toString”“valueOf”,朋友以为我写了bug,急得直催我改。后来查了文档才知道,for...in会遍历原型链上的属性,得加个hasOwnProperty判断才行。这件事让我意识到,选对遍历方法真的能少走很多弯路,今天就把我整理的“遍历手册”分享给你,都是实战中用出来的经验,看完就能直接上手。

最常用的4种对象遍历方法:原理+实战,看完就能用

前端开发中,遍历对象的场景真的太多了——展示用户信息、计算购物车总价、渲染表单字段、处理接口返回的复杂数据……我 了最常用的4种方法,每个都讲清楚“是什么”“怎么用”“什么时候用”,你照着做就行。

  • for...in:老牌方法,但得会“过滤”
  • for...in应该是很多人入门时学的第一个遍历对象的方式,它的原理很简单:遍历对象的所有可枚举属性,包括原型链上的属性。可枚举属性就是那些在定义时“enumerable”设为true的属性,比如我们平时直接写的const obj = { a: 1 }a就是可枚举的。但问题来了,原型链上的属性也会被遍历到,比如Object.prototype上的方法,这就是我之前踩坑的原因。

    举个例子,你有个用户对象:

    const user = { name: '张三', age: 28 };
    

    // 给原型链加个方法

    Object.prototype.getFullName = function() {

    return this.name;

    };

    for...in遍历的话,会得到nameagegetFullName三个属性——getFullName是原型链上的,我们不需要展示它。这时候就得加个hasOwnProperty判断,只遍历对象自身的属性:

    for (let key in user) {
    

    if (user.hasOwnProperty(key)) {

    console.log(${key}: ${user[key]}); // 输出name: 张三,age: 28

    }

    }

    我去年做用户信息表单的时候,就是用这个方法遍历字段,把每个键值对渲染成。比如key是“name”,就生成,既简单又实用。提示:如果你的项目里经常用for...in,可以写个小工具函数封装一下,比如function iterateObj(obj, callback) { for (let key in obj) { if (obj.hasOwnProperty(key)) callback(key, obj[key]); } },这样更高效。

  • Object.keys():只拿键名,适合统计或处理键
  • ES5新增的Object.keys()方法,会返回对象自身可枚举键名的数组,不包含原型链上的属性。比如上面的user对象,Object.keys(user)会返回['name', 'age'],直接排除了原型上的getFullName

    这个方法适合什么场景呢?比如你想统计对象有多少个字段,或者需要把键名转成数组做进一步处理。我做电商后台的商品筛选功能时,需要把筛选条件对象的键名拼成URL参数,比如{ category: '电器', price: '100-500' },用Object.keys()拿到['category', 'price'],然后forEach遍历拼成category=电器&price=100-500

    const filterObj = { category: '电器', price: '100-500' };
    

    const params = Object.keys(filterObj).reduce((acc, key) => {

    acc[key] = filterObj[key];

    return acc;

    }, {});

    // 然后用qs.stringify(params)转成URL参数

    这样比用for...in省了hasOwnProperty的判断,代码更简洁。亲测:如果你的对象没有原型链上的额外属性,Object.keys()是比for...in更高效的选择。

  • Object.values():只取值,计算总和或统计超方便
  • Object.keys()对应,Object.values()会返回对象自身可枚举值的数组。比如购物车对象const cart = { apple: 10, banana: 5, orange: 8 }Object.values(cart)会返回[10, 5, 8],直接拿到所有商品的价格。

    我做生鲜小程序的购物车页面时,就用这个方法计算总价——用户选了商品后,实时更新总价:

    const totalPrice = Object.values(cart).reduce((total, price) => total + price, 0);
    

    console.log(totalPrice); // 23

    是不是超方便?不用再遍历键名再取value,一步到位。还有一次做数据统计,需要统计用户的积分来源(比如{ sign: 5, share: 10, purchase: 20 }),用Object.values()拿到所有积分值,再求和就能得到总积分,比写循环简洁多了。

  • Object.entries():键值对一起拿,渲染或配对首选
  • ES6新增的Object.entries()方法,会返回对象自身可枚举键值对的数组,每个元素是[key, value]的形式。比如订单对象const order = { orderId: '12345', createTime: '2024-05-20', totalPrice: 200 }Object.entries(order)会返回[['orderId', '12345'], ['createTime', '2024-05-20'], ['totalPrice', 200]]

    这个方法的好处是可以配合for...of循环,同时拿到键和值,不用再单独取。我做订单详情页的时候,就是用它渲染字段:

    const orderDetails = document.querySelector('.order-details');
    

    for (let [key, value] of Object.entries(order)) {

    const div = document.createElement('div');

    div.innerHTML = ${key}: ${value};

    orderDetails.appendChild(div);

    }

    直接把键值对渲染成页面元素,比用Object.keys()再取value省了一步。还有一次做配置项的开关功能,每个配置项是{ key: 'enableNotification', value: true, label: '开启通知' },用Object.entries()遍历,把每个项渲染成开关组件,效率很高。注意Object.entries()返回的数组顺序和插入顺序一致(除了数字键,后面会讲),所以渲染出来的字段顺序和你定义的一样,不用担心乱序。

    为了让你更清楚这四个方法的差异,我整理了一个对比表格(根据MDN文档和项目经验 ):

    方法名称 遍历内容 是否包含原型链 适用场景
    for…in 可枚举属性 是(需过滤) 需遍历所有可枚举属性(含原型)
    Object.keys() 自身可枚举键名 只需键名,统计或处理键
    Object.values() 自身可枚举值 只需值,计算总和或统计
    Object.entries() 自身可枚举键值对 需同时处理键和值,渲染或配对

    避坑指南:这些错误我踩过,你别再犯

    掌握了方法还不够,得知道哪些坑不能踩——我之前踩过的错误,你别再犯了。

  • 遍历顺序的“小惊喜”:数字键会优先排
  • 你有没有遇到过这样的情况?对象的键是“10”“2”“a”,遍历出来的顺序是2、10、a?我去年做商品编号遍历功能时就遇到了——当时商品对象的键是“1001”“2002”“a001”,用Object.keys()遍历出来的顺序是“1001”“2002”“a001”?不对,其实数字键会被JavaScript当作“数组索引”处理,优先按升序排列。比如键是“2”“10”“a”,遍历顺序是2、10、a,而字符串键按插入顺序排列。

    MDN文档里明确说:“Object.keys()Object.values()Object.entries()的遍历顺序遵循ECMAScript 2015规范,对于数字索引的属性,按升序排列;对于其他字符串属性,按插入顺序排列。”所以如果你的对象有数字键,要注意遍历顺序可能和你插入的顺序不一样。比如我做的商品编号功能,后来把数字键改成了“p1001”“p2002”,这样就是字符串键,遍历顺序就和插入顺序一致了。 :如果需要固定顺序,尽量用字符串键(带前缀),或者用MapMap的遍历顺序严格按插入顺序)。

  • 非枚举属性的“隐形”问题:遍历不到不是bug
  • 有些属性是“不可枚举”的,比如用Object.defineProperty定义的属性,默认enumerablefalse。比如:

    const obj = {};
    

    Object.defineProperty(obj, 'secret', {

    value: '123',

    enumerable: false // 默认就是false

    });

    这时候用for...inObject.keys()都遍历不到“secret”这个属性。我之前做用户权限系统时,框架把用户的权限标识存在了不可枚举属性里,我一开始用Object.keys()遍历不到,还以为是框架的bug,后来查了Object.getOwnPropertyDescriptors(obj)才发现,这个属性的enumerablefalse

    所以如果遇到遍历不到某个属性的情况,先检查一下它的可枚举性——用Object.getOwnPropertyDescriptor(obj, 'key')看看enumerable的值。比如:

    const descriptor = Object.getOwnPropertyDescriptor(obj, 'secret');
    

    console.log(descriptor.enumerable); // false

    这样就能快速定位问题了。提示:框架或库的内部属性 often是不可枚举的,避免被意外遍历到,所以遇到这种情况不用慌,不是你的代码错了。

  • for...of不能直接遍历对象:得转成可迭代数组
  • 很多人学了for...of之后,以为能像遍历数组一样遍历对象,结果报错“obj is not iterable”。其实对象不是“可迭代对象”(iterable),只有数组、字符串、MapSet这些实现了Symbol.iterator接口的对象才能用for...of遍历。

    所以要遍历对象的话,得先把它转成可迭代的数组,比如用Object.entries()

    const obj = { a: 1, b: 2 };
    

    // 错误写法:for (let item of obj) { ... }

    // 正确写法:

    for (let [key, value] of Object.entries(obj)) {

    console.log(key, value); // a 1,b 2

    }

    我之前做项目时就犯过这个错,直接用for...of遍历对象,结果控制台红了一片,后来查了ECMAScript规范才知道原因——对象没有默认的迭代器,得自己实现或者转成数组。延伸:如果你想让对象支持for...of,可以自己定义Symbol.iterator方法,比如:

    const obj = { a: 1, b: 2 };
    

    obj[Symbol.iterator] = function* () {

    for (let key of Object.keys(this)) {

    yield [key, this[key]];

    }

    };

    // 现在可以用for...of遍历了

    for (let [key, value] of obj) {

    console.log(key, value); // a 1,b 2

    }

    不过这种情况很少见,一般用Object.entries()就够了。

    你有没有遇到过遍历对象的奇怪问题?比如遍历顺序乱了、属性隐形了?欢迎在评论区告诉我,我帮你一起排查!


    本文常见问题(FAQ)

    for…in遍历对象时为什么会出现奇怪的属性?

    这是因为for…in会遍历对象原型链上的可枚举属性,比如Object.prototype上的toString、valueOf这些默认方法。我之前帮朋友做电商订单详情页时就踩过这坑,用for…in遍历订单对象想展示商品名称、数量,结果页面上多了一堆原型链里的方法名,朋友以为我写了bug。解决办法很简单,遍历的时候加个hasOwnProperty判断就行,比如for (let key in obj) { if (obj.hasOwnProperty(key)) { // 处理要展示的属性 } },这样就只遍历对象自身的属性了。

    为什么用for…of直接遍历对象会报错?

    因为JavaScript里的对象不是“可迭代对象”,只有数组、字符串、Map这种实现了Symbol.iterator接口的类型,才能用for…of直接遍历。我之前学for…of的时候也犯过这错,直接用它遍历用户信息对象,结果控制台红了一片。想解决的话,先用Object.entries()把对象转成键值对数组,比如const entries = Object.entries(obj),再用for…of遍历entries,这样就能同时拿到键和值,像for (let [key, value] of Object.entries(obj)) { // 处理逻辑 }就很顺手。

    为什么有些对象属性遍历不到?是我代码写错了吗?

    不一定是代码错了,大概率是这个属性是“不可枚举”的。比如用Object.defineProperty定义属性时,默认enumerable(可枚举性)是false,这种属性不会被for…in、Object.keys()这些方法遍历到。我之前做用户权限系统时,框架把用户的权限标识存在不可枚举属性里,一开始用Object.keys()遍历不到,还以为是框架出问题了,后来用Object.getOwnPropertyDescriptor(obj, ‘权限属性名’)查了下,发现enumerable果然是false。要是遇到这种情况,先检查属性的可枚举性,不用急着改代码。

    遍历对象时数字键的顺序不对怎么办?

    这是因为JavaScript会把数字键当作“数组索引”处理,优先按升序排列,比如你插入的顺序是“10”“2”,遍历出来会是2、10,和预期不一样。我去年做商品编号功能时就遇到过,商品键是“1001”“2002”,结果遍历顺序和我插入的顺序不符。解决办法有两个:要么把数字键改成带前缀的字符串,比如“p1001”“p2002”,这样就按插入顺序排列;要么用Map,Map的遍历顺序严格跟着你插入的顺序来,不会乱。

    Object.values()适合用来做什么场景?

    Object.values()最适合只需要对象“值”的场景,比如计算总和、统计数据。我做生鲜小程序购物车页面时,用它算总价特别方便——购物车对象是{ apple: 10, banana: 5, orange: 8 },用Object.values(cart)直接拿到[10,5,8],再用reduce((total, price) => total + price, 0)求和,一句话就能算出总价格。还有一次做用户积分统计,积分对象是{ sign:5, share:10, purchase:20 },用Object.values()拿到所有积分值再求和,比写循环省了不少代码,还不容易错。

    原文链接:https://www.mayiym.com/54872.html,转载请注明出处。
    0
    显示验证码
    没有账号?注册  忘记密码?

    社交账号快速登录

    微信扫一扫关注
    如已关注,请回复“登录”二字获取验证码