本文介绍在JavaScript中遍历数组或对象时常用的一些方法,以及使用for循环时的Tricks和Best Practices.
基本上,数组和对象的遍历会有如下三种方案:
Object.keys
或Object.getOwnPropertyNames
遍历对象属性:一般与前面二种配合使用本文只介绍第一部分,即for循环。
这是JavaScript中最传统也是最常使用的遍历数组的方法,这里有一点需要注意,就是使用var
定义的变量的作用域始终是所包含的scope,除非使用ES2015+提供的let。
ES2015新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。
下面是使用let
后的代码,大家可以看到i
只在for block内有效,在
如果浏览器不支持let,可以使用Babel将你的ES2015+代码编译为与ES5兼容的代码,如上面这段代码,使用Babel后就会被编译为:
从上面代码,可以看出,在for循环中,变量i
编译后变为_i
了,那自然在代码块外面引用i
时会报错了。
enumerable
为true
),同时还包括继承属性arr.foo
添加的foo
属性)以及原型链上可枚举属性var
定义的变量的作用域始终是所包含的scope遍历数组索引,但是同时也会遍历数组的属性值以及原型链上可枚举属性
遍历对象时,对象属性值的遍历顺序是不保证的。
ES3标准规定for…in语句的属性遍历的顺序是由对象定义时属性的书写顺序决定的。
The mechanics of enumerating the properties (step 5 in the first algorithm, step 6 in the second) is implementation dependent. The order of enumeration is defined by the object. …
而在ES5标准中对 for…in语句的遍历机制又做了调整,属性遍历的顺序是没有被规定的,也就是说并没有规定对JavaScript的Object
类型中的属性的存储顺序。
The mechanics and order of enumerating the properties (step 6.a in the first algorithm, step 7.a in the second) is not specified. Properties of the object being enumerated may be deleted during enumeration….
对于对象遍历来说,这个并不是什么大问题,因为它本来就是无序的。但是你并不太可能想遍历数组时也是无序的,因为这会让你得到意想不到的结果。
遍历对象时,大多数时候我们并不想遍历继承属性,这时可以在遍历时通过hasOwnProperty()
方法跳过继承属性。
ES2015中引入了Iterator的概念,它为你迭代集合中的每一个元素提供了更大的便利。Iterator属于一种接口规格,任何数据结构只要部署这个接口,就可以完成遍历操作,即依次处理该结构的所有成员。它的作用有两个,
在ES2015中,遍历操作特指for…of循环,即Iterator接口主要供for…of消费。for…of与其它的遍历一样,除了它是专门用于与Iterables对象(部署了Iterator的对象,Array
或是String
都是Iterables)一起工作的。
关于Iterator和Iterable部分,可以参考ECMAScript 6 入门。
ES2015中,一个数据结构只要部署了Symbol.iterator
方法,就被视为具有iterator接口,就可以用for…of循环遍历它的成员。也就是说,for…of循环内部调用的是数据结构的Symbol.iterator
方法。
for…of循环可以使用的范围包括数组、Set
和Map
结构、某些类似数组的对象(比如arguments
对象、DOM NodeList
对象)、Generator
对象,以及字符串。
JavaScript原有的for…in循环,只能获得对象的属性名,不能直接获取属性值。而for…of循环,允许遍历获得键值。
上面代码表明,for…in循环读取属性名,for…of循环读取属性值。如果要通过for…of循环,获取数组的索引,可以借助数组实例的entries()
方法和keys()
方法。
只有Firefox提供,用于遍历对象属性值,不建议使用。
由于数组遍历有上述的这些问题,也许你永远也不会用for…in去遍历数组了。那么我们有如下的替代选择:
hasOwnProperty()
Object.keys()
或是Object.getOwnPropertyNames()
和Array.prototype.forEach
遍历方法