二、对象遍历方法
1. for in
for…in
主要用于循环对象属性。循环中的代码每执行一次,就会对对象的属性进行一次操作。其语法如下:
for (var in object) { 执行的代码块 } 复制代码
其中两个参数:
- var:必须。指定的变量可以是数组元素,也可以是对象的属性。
- object:必须。指定迭代的的对象。
var obj = {a: 1, b: 2, c: 3}; for (var i in obj) { console.log('键名:', i); console.log('键值:', obj[i]); } 复制代码
输出结果:
键名: a 键值: 1 键名: b 键值: 2 键名: c 键值: 3 复制代码
注意:
- for in 方法不仅会遍历当前的对象所有的可枚举属性,还会遍历其原型链上的属性。
2. Object.keys()、Object.values()、Object.entries()
这三个方法都用来遍历对象,它会返回一个由给定对象的自身可枚举属性(不含继承的和Symbol属性)组成的数组,数组元素的排列顺序和正常循环遍历该对象时返回的顺序一致,这个三个元素返回的值分别如下:
- Object.keys():返回包含对象键名的数组;
- Object.values():返回包含对象键值的数组;
- Object.entries():返回包含对象键名和键值的数组。
let obj = { id: 1, name: 'hello', age: 18 }; console.log(Object.keys(obj)); // 输出结果: ['id', 'name', 'age'] console.log(Object.values(obj)); // 输出结果: [1, 'hello', 18] console.log(Object.entries(obj)); // 输出结果: [['id', 1], ['name', 'hello'], ['age', 18] 复制代码
注意
- Object.keys()方法返回的数组中的值都是字符串,也就是说不是字符串的key值会转化为字符串。
- 结果数组中的属性值都是对象本身可枚举的属性,不包括继承来的属性。
3. Object.getOwnPropertyNames()
Object.getOwnPropertyNames()
方法与Object.keys()
类似,也是接受一个对象作为参数,返回一个数组,包含了该对象自身的所有属性名。但它能返回不可枚举的属性。
let a = ['Hello', 'World']; Object.keys(a) // ["0", "1"] Object.getOwnPropertyNames(a) // ["0", "1", "length"] 复制代码
这两个方法都可以用来计算对象中属性的个数:
var obj = { 0: "a", 1: "b", 2: "c"}; Object.getOwnPropertyNames(obj) // ["0", "1", "2"] Object.keys(obj).length // 3 Object.getOwnPropertyNames(obj).length // 3 复制代码
4. Object.getOwnPropertySymbols()
Object.getOwnPropertySymbols()
方法返回对象自身的 Symbol 属性组成的数组,不包括字符串属性:
let obj = {a: 1} // 给对象添加一个不可枚举的 Symbol 属性 Object.defineProperties(obj, { [Symbol('baz')]: { value: 'Symbol baz', enumerable: false } }) // 给对象添加一个可枚举的 Symbol 属性 obj[Symbol('foo')] = 'Symbol foo' Object.getOwnPropertySymbols(obj).forEach((key) => { console.log(obj[key]) }) // 输出结果:Symbol baz Symbol foo 复制代码
5. Reflect.ownKeys()
Reflect.ownKeys() 返回一个数组,包含对象自身的所有属性。它和Object.keys()类似,Object.keys()返回属性key,但不包括不可枚举的属性,而Reflect.ownKeys()会返回所有属性key:
var obj = { a: 1, b: 2 } Object.defineProperty(obj, 'method', { value: function () { alert("Non enumerable property") }, enumerable: false }) console.log(Object.keys(obj)) // ["a", "b"] console.log(Reflect.ownKeys(obj)) // ["a", "b", "method"] 复制代码
注意:
- Object.keys() :相当于返回对象属性数组;
- Reflect.ownKeys() :相当于
Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj)
。
总结:
对象方法 | 遍历基本属性 | 遍历原型链 | 遍历不可枚举属性 | 遍历Symbol |
for in | 是 | 是 | 否 | 否 |
Object.keys() | 是 | 否 | 否 | 否 |
Object.getOwnPropertyNames() | 是 | 否 | 是 | 否 |
Object.getOwnPropertySymbols() | 否 | 否 | 是 | 是 |
Reflect.ownKeys() | 是 | 否 | 是 | 是 |
三、其他遍历方法
1. for
for循环是应该是最常见的循环方式了,它由三个表达式组成,分别是声明循环变量、判断循环条件、更新循环变量。这三个表达式用分号分隔。可以使用临时变量将数组的长度缓存起来,避免重复获取数组长度,当数组较大时优化效果会比较明显。
const arr = [1,2,3,4,5] for(let i = 0, len = arr.length; i < len; i++ ){ console.log(arr[i]) } 复制代码
在执行的时候,会先判断执行条件,再执行。for循环可以用来遍历数组,字符串,类数组,DOM节点等。可以改变原数组。
2. while
while
循环中的结束条件可以是各种类型,但是最终都会转为布尔值,转换规则如下。
- Boolean:true为真,false为假;
- String:空字符串为假,所有非空字符串为真;
- Number:0为假,非0数字为真;
- null/Undefined/NaN:全为假;
- Object:全为真。
let num = 1; while (num < 10){ console.log(num); num ++; } 复制代码
while
和for
一样,都是先判断,再执行。只要指定条件为 true,循环就可以一直执行代码。
3. do / while
该方法会先执行再判断,即使初始条件不成立,do/while
循环也至少会执行一次。
let num = 10; do { console.log(num); num--; } while(num >= 0); console.log(num); //-1 复制代码
不建议使用do / while来遍历数组。
4. for await of
for await...of
方法被称为异步迭代器,该方法是主要用来遍历异步对象。它是ES2018中引入的方法。
for await...of
语句会在异步或者同步可迭代对象上创建一个迭代循环,包括 String,Array,类数组,Map, Set和自定义的异步或者同步可迭代对象。这个语句只能在 async function
内使用:
function Gen (time) { return new Promise((resolve,reject) => { setTimeout(function () { resolve(time) },time) }) } async function test () { let arr = [Gen(2000),Gen(100),Gen(3000)] for await (let item of arr) { console.log(Date.now(),item) } } test() 复制代码
输出结果: