JS中轻松遍历对象属性的⼏种⽅式
英⽂原⽂:
译者:前端⼩智
为了保证的可读性,本⽂采⽤意译⽽⾮直译。
⾃⾝可枚举属性
Object.keys() ⽅法会返回⼀个由⼀个给定对象的⾃⾝可枚举属性组成的数组,数组中属性名的排列顺序和使⽤ in 循环遍历该对象时返回的顺序⼀致。如果对象的键-值都不可枚举,那么将返回由键组成的数组。
这是合理的,因为⼤多数时候只需要关注对象⾃⾝的属性。
来看看⼀个对象拥有⾃⾝和继承属性的例⼦,Object.keys()只返回⾃⼰的属性键:
let simpleColors = {
colorA: 'white',
colorB: 'black'
};
let natureColors = {
colorC: 'green',
colorD: 'yellow'
};
Object.setPrototypeOf(natureColors, simpleColors);
Object.keys(natureColors); // => ['colorC', 'colorD']
natureColors['colorA']; // => 'white'
natureColors['colorB']; // => 'black'
复制代码
Object.setPrototypeOf() ⽅法设置⼀个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另⼀个对象或 null。
Object.keys(natureColors)返回natureColors对象的⾃⾝可枚举属性键:['colorC','colorD']。
natureColors包含从simpleColors原型对象继承的属性,但是Object.keys()函数会跳过它们。
Object.values() 和 ies() 也都是返回⼀个给定对象⾃⾝可枚举属性的键值对数组
// ...
Object.values(natureColors);
// => ['green', 'yellow']
// => [ ['colorC', 'green'], ['colorD', 'yellow'] ]
复制代码
现在注意与for..in语句的区别,for..in不仅可以循环枚举⾃⾝属性还可以枚举原型链中的属性
// ...
let enumerableKeys = [];
for (let key in natureColors) {
enumerableKeys.push(key);
}
enumerableKeys; // => ['colorC', 'colorD', 'colorA', 'colorB']
复制代码
enumerableKeys数组包含natureColors⾃⾝属性键: 'colorC'和'colorD'。
另外for..in也遍历了从simpleColors原型对象继承的属性
2. Object.values() 返回属性值
**Object.values()**⽅法返回⼀个给定对象⾃⾝的所有可枚举属性值的数组,值的顺序与使⽤in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。
来个例⼦,使⽤Object.keys()收集keys,然后通过 key 去对象取对应的值:
let meals = {
mealA: 'Breakfast',
mealB: 'Lunch',
mealC: 'Dinner'
};
for (let key of Object.keys(meals)) {
let mealName = meals[key];
// ... do something with mealName
console.log(mealName);
}
/
/ 'Breakfast' 'Lunch' 'Dinner'
复制代码
meal是⼀个普通对象。使⽤Object.keys(meals)和枚举的f循环获取对象键值。
代码看起来很简单,但是,let mealName = meals[key] 没有多⼤的必要,可以进⼀步优化,如下:
let meals = {
mealA: 'Breakfast',
mealB: 'Lunch',
mealC: 'Dinner'
};
js原型和原型链的理解for (let mealName of Object.values(meals)) {
console.log(mealName);
}
// 'Breakfast' 'Lunch' 'Dinner'
复制代码
因为Object.values(meals)返回数组中的对象属性值,所以可以直接在 f 中简化。 mealName直接在循环中赋值。
**ies()**⽅法返回⼀个给定对象⾃⾝可枚举属性的键值对数组,其排列与使⽤ in 循环遍历该对象时返回的顺序⼀致(区别在于 for-in 循环也枚举原型链中的属性)。
可能直接使⽤这些键值对不怎么⽅便,但可以通过数组解构赋值⽅式访问键和值就变得⾮常容易,如下所⽰:
let meals = {
mealA: 'Breakfast',
mealB: 'Lunch',
mealC: 'Dinner'
};
for (let [key, value] ies(meals)) {
console.log(key + ':' + value);
}
// 'mealA:Breakfast' 'mealB:Lunch' 'mealC:Dinner'
复制代码
如上所⽰,因为 ies()返回⼀个与数组解构赋值兼容的集合,因此不需要为赋值或声明添加额外的⾏。
当普通对象要转换成 Map 时ies() 就很有⽤,因为ies() 返回的格式与Map构造函数接受的格式完全相同:(key,value)。
使⽤常规的Map构造函数可以将⼀个⼆维键值对数组转换成⼀个Map对象。
来个例⼦,让⼈缓缓:
let greetings = {
morning: 'Good morning',
midday: 'Good day',
evening: 'Good evening'
};
let greetingsMap = new ies(greetings));
<('morning'); // => 'Good morning'
<('midday'); // => 'Good day'
<('evening'); // => 'Good evening'
复制代码
Map 对象保存键值对。任何值(对象或者原始值) 都可以作为⼀个键或⼀个值。
有趣的是,Map提供了与Object.values()和ies() 等效的⽅法(只是它们返回Iterators),以便为Map实例提取属性值或键值对:
Map.prototype.values() 等价于Object.values()
ies() 等价于ies()
map是普通对象的改进版本,可以获取 map 的⼤⼩(对于普通对象,必须⼿动获取),并使⽤任意对象类型作为键(普通对象使⽤字符串基元类型作为键)。
让我们看看返回.values()和.entries()的map的⽅法:
// ...
[...greetingsMap.values()];
// => ['Good morning', 'Good day', 'Good evening']
[...ies()];
// => [ ['morning', 'Good morning'], ['midday', 'Good day'],
// ['evening', 'Good evening'] ]
复制代码
注意,greetingsMap.values()和ies()返回迭代器对象。若要将结果放⼊数组,扩展运算符…是必要的。
对象属性的顺序
JS 对象是简单的键值映射,因此,对象中属性的顺序是微不⾜道的,在⼤多数情况下,不应该依赖它。
在ES5和早期标准中,根本没有指定属性的顺序。
然⽽,从ES 6开始,属性的顺序是基于⼀个特殊的规则的,除⾮特指按照时间排序。通过两个新⽅法OwnPropertyNames和Reflect.ownKeys来编写⽰例讲解这⼀属性排序规则。
数字:当属性的类型时数字类型时,会按照数字的从⼤到⼩的顺序进⾏排序;
字符串:当属性的类型是字符串时,会按照时间的先后顺序进⾏排序;
Symbol:当属性的类型是Symbol时,会按照时间的先后顺序进⾏排序。
如果需要有序集合,建议将数据存储到数组或Set中。
总结
Object.values() 和ies() 是为JS开发⼈员提供新的标准化辅助函数的另⼀个改进步骤。
注意,Object.values()和ies()返回数据的顺序是不确定的,所以不要依赖该⽅式。
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了⼤量的时间进⾏log 调试,这边顺便给⼤家推荐⼀个好⽤的BUG监控⼯具。交流(欢迎加⼊,⼯作⽇都会发红包,互动讨论技术)
⼲货系列⽂章汇总如下,觉得不错点个Star,欢迎加互相学习。
出处:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论