本文主要是对JavaScript对象遍历方法做一个总结,比如Object最常见的遍历方法方法就是使用for…in…,但其有一定的局限性,比如只能遍历可枚举属性。虽然Object无法直接使用for循环和forEach,但是经过Reflect.ownKeys / Object.getOwnPropertyNames / Object.getOwnPropertySymbols / Object.keys等方法转换直接得到Object中key值的集合后,是可以通过for循环和forEach来遍历的
前言
本篇内容将按照下图展开:
遍历Object
Object最常见的遍历方法方法就是使用for…in…,但其有一定的局限性,比如只能遍历可枚举属性。虽然Object无法直接使用for循环和forEach,但是经过Reflect.ownKeys / Object.getOwnPropertyNames / Object.getOwnPropertySymbols / Object.keys等方法转换直接得到Object中key值的集合后,是可以通过for循环和forEach来遍历的。
方法 | 获取属性种类 |
---|---|
Object.keys | 可枚举属性 |
Object.getOwnPropertySymbols | Symbol属性 |
Object.getOwnPropertyNames | 可枚举属性和不可枚举属性 |
Reflect.ownKeys | 可枚举属性、不可枚举属性和Symbol属性 |
比如现在有个对象,其中有3个属性,分别是可枚举属性、不可枚举属性和Symbol属性:
let person = { name : \'xiaoming\'}person[Symbol(\'sex\')] = \'man\';Object.defineProperty(person, \'age\', { value : 18, writable: true, configurable: false, enumerable: false})
使用for…in…遍历
for(let key in person){ console.log(\'key : \' + key + \' , value : \' + person[key]);}
输出结果:
使用Object.keys + for循环遍历
let keys2 = Object.keys(person);for(let index = 0, length = keys2.length; index < length; index++){ let key = keys2[index]; let value = person[key]; console.log(\'key : \' + key + \' , value : \' + value);}
输出结果:
使用Object.getOwnPropertyNames + for循环遍历
let names = Object.getOwnPropertyNames(person);for(let index = 0, length = names.length; index < length; index++){ let key = names[index]; let value = person[key]; console.log(\'key : \' + key + \' , value : \' + value);}
输出结果:
使用Object.getOwnPropertySymbols + for循环遍历
let symbols = Object.getOwnPropertySymbols(person);for(let index = 0, length = symbols.length; index < length; index++){ let key = symbols[index]; let value = person[key]; typeof key === \'symbol\' ? key = Symbol.prototype.toString.call(key) : \'\'; console.log(\'key : \' + key + \' , value : \' + value);}
输出结果:
使用Reflect.ownKeys + for循环遍历
let keys = Reflect.ownKeys(person);for(let index = 0, length = keys.length; index < length; index++){ let key = keys[index]; let value = person[key]; typeof key === \'symbol\' ? key = Symbol.prototype.toString.call(key) : \'\'; console.log(\'key : \' + key + \' , value : \' + value);}
输出结果:
遍历Array
遍历Array可以使用for循环,也可以使用for…in…和for…of…,并且Array的原型中还有forEach函数和map函数可用来遍历Array对象。
测试数据:
let arr = [\'item_1\', \'item_2\', \'item_3\', \'item_4\', \'item_5\'];
使用for…in…遍历
for(let index in arr){ console.log(\'index : \' + arr[index]);}
输出结果:
使用for循环遍历
for(let index = 0, length = arr.length; index < length; index += 1){ console.log(\'index : \' + arr[index]);}
输出结果:
使用Array.prototype.forEach遍历
Array.prototype.forEach.call(arr, (value) => { console.log(\'value : \' + value);})
输出结果:
使用Array.prototype.map遍历
Array.prototype.map.call(arr, (value) => { console.log(\'value : \' + value);})
输出结果:
map方法会根据原数组中的每个元素调用函数后返回的数据创建一个新数组。
使用for…of…遍历
for(let value of arr){ console.log(\'value : \' + value);}
输出结果:
遍历Map
遍历Map一般是两种,一是直接使用for…of…或者Map.prototype.forEach,二是通过Map.prototype.entries / Map.prototype.keys / Symbol.iterator获取Map对象的迭代器,再通过for…of…来遍历迭代器。
测试数据:
let map = new Map();map.set(\'key_1\', \'value_1\');map.set(\'key_2\', \'value_2\');map.set(\'key_3\', \'value_3\');map.set(\'key_4\', \'value_4\');map.set(\'key_5\', \'value_5\');
使用for…of…遍历
for(let [key, value] of map){ console.log(\'key : \' + key + \' value : \' + value);}
输出结果:
使用Map.prototype.forEach遍历
Map.prototype.forEach.call(map, (value, key) => { console.log(\'key : \' + key + \' value : \' + value);})
输出结果:
使用Map.prototype.entries + for…of…遍历
let iterator = Map.prototype.entries.call(map);for(let item of iterator){ console.log(\'item : \' + item);}
输出结果:
使用Map.prototype.keys + for…of…遍历
let keys = Map.prototype.keys.call(map);for(let key of keys){ console.log(\'key : \' + key + \' value : \' + Map.prototype.get.call(map, key));}
输出结果:
使用Symbol.iterator + for…of…遍历
let iterator2 = map[Symbol.iterator]();for(let item of iterator2){ console.log(\'item : \' + item);}
输出结果:
遍历Set
遍历Set和遍历Map差不多,Map有的方法Set都有,但是有一个差别:Map是以键值对的形式去存储数据的,其中键是唯一;而Set存储的只有值,其值是唯一的。
遍历Set一般也是两种,一是直接使用for…of…或者Set.prototype.forEach,二是通过Set.prototype.values / Symbol.iterator获取Map对象的迭代器,再通for…of…来遍历迭代器
像Set.prototype.entries / Set.prototype.keys虽然也可以达到遍历Set对象的效果,但是由于其将value当做key,笔者感觉这两个方法与上文中Map.prototype.entries / Map.prototype.keys逻辑上差别不大,故而不再赘述。
测试数据:
let set = new Set();set.add(\'value_1\');set.add(\'value_2\');set.add(\'value_3\');set.add(\'value_4\');set.add(\'value_5\');
使用for…of…遍历
for(let item of set){ console.log(\'item : \' + item);}
输出结果:
使用Set.prototype.forEach遍历
let iterator = Set.prototype.values.call(set);for(let value of iterator){ console.log(\'value : \' + value);}
输出结果:
使用Set.prototype.values + for…of…遍历
let iterator = Set.prototype.values.call(set);for(let value of iterator){ console.log(\'value : \' + value);}
输出结果:
使用Symbol.iterator + for…of…遍历
let iterator2 = set[Symbol.iterator]();for(let value of iterator2){ console.log(\'value : \' + value);}
输出结果:
尾言
笔者才疏学浅,慌忙之下难免有遗漏或是疏忽,如有错误之处,还望各位看官不吝赐教,笔者在此感谢。