数组是一种很重要的数据结构。那么我们如何遍历数组呢?
我们如何遍历数组中的元素?20年前JavaScript刚萌生时,你可能这样实现数组遍历:
for (var index = 0; index < myArray.length; index++) {
console.log(myArray[index]);
}
自ES5正式发布后,你可以使用内建的forEach方法来遍历数组:
myArray.forEach(function (value,index) {
(index+":"+value);
});
这段代码看起来更加简洁,但这种方法也有一个小缺陷:你不能使用break语句中断循环,也不能使用return语句返回到外层函数。另外,forEach方法是Array对象的方法,所以对于DOM的类数组,如NodeList对象,则不能遍历。
当然,如果只用for循环的语法来遍历数组元素也很不错。
那么,你一定想尝试一下for-in循环:
for (var index in myArray) { // 千万别这样做
(myArray[index]);
}
这绝对是一个糟糕的选择,为什么呢?
- 在这段代码中,赋给index的值不是实际的数字,而是字符串“0”、“1”、“2”,此时很可能在无意之间进行字符串算数计算,例如:“2” + 1 == “21”,这给编码过程带来极大的不便。
- 作用于数组的for-in循环体除了遍历数组元素外,还会遍历自定义属性。举个例子,如果你的数组中有一个可枚举属性,循环将额外执行一次,遍历到名为“name”的索引。就连数组原型链上的属性都能被访问到。
- 最让人震惊的是,在某些情况下,这段代码可能按照随机顺序遍历数组元素
- 简而言之,for-in是为普通对象设计的,你可以遍历得到字符串类型的键,因此不适用于数组遍历
强大的for-of循环
每个具有遍历器方法的对象都称为”可遍历”对象。
for of遍历一种数据集合时,首先会寻找这个集合是否有遍历器方法,没有就抛出错误,有就调用这个方法。遍历器方法返回一个遍历对象,遍历对象的根本特征就是具有next方法。每次调用next方法,都会返回一个代表当前成员的信息对象,具有value和done两个属性。
for of就是不断调用next方法来遍历的
ES6规定,遍历器方法保存在对象的[]属性中(这个属性的名字是内置的Symbol值,防止重名)
let obj = {
a:1,
b:2
};
console.log(obj[]); //undefined
for(let x of obj){
console.log(x);
}
// Uncaught TypeError: obj is not iterable
对象没有默认的iterator接口([]),所以用for of遍历时就抛出了错误。
我们来给这个对象定义一个[]属性。
obj[]=function(){
return {
next: function(){
return { value:1, done:false }
}
};
}
for(let x of obj){
(x);
}
有了遍历器方法后,for of就能遍历这个对象了,不过done属性为false,这个遍历就永远不会结束,它会一直打印1。
对象(Object)之所以没有默认部署Iterator接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定。本质上,遍历器是一种线性处理,对于任何非线性的数据结构,部署遍历器接口,就等于部署一种线性转换。不过,严格地说,对象部署遍历器接口并不是很必要,因为这时对象实际上被当作Map结构使用,ES5没有Map结构,而ES6原生提供了。
具有[]属性的对象有:数组、某些类似数组的对象、Set和Map结构。我们可以自己定义对象的[]属性来覆盖默认的[]属性
let arr=[1,2,3];
arr[]=function(){
let index=0;
return {
next:function(){
if(index<){
index++;
return {
value:1,
done:false
}
}else{
return {
value:"遍历结束",
done:true
}
}
}
}
};
//模拟for of循环
let iterator = arr[]();
iterator.next(); // {value: 1, done: false}
iterator.next(); // {value: 1, done: false}
iterator.next(); // {value: 1, done: false}
iterator.next(); // {value: "遍历结束", done: true}
for(let x of arr){
(x); // 1 1 1
}
ES6数组遍历方法
ES6给数组原型添加了几种新的遍历数组方法:() ()和()(浏览器支持不好)
for…of循环内部调用的是数据结构的方法来遍历。
() ()和()这些方法返回一个新的方法,for of内部调用的就是新迭代对象
()
作用:遍历数组的键值对
参数:无
返回值:返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对
var arr = ["a", "b", "c"];
var iterator = ();
(iterator); // Array Iterator {}
(iterator.next()); // {value: [0, "a"], done:false}
(iterator.next()); // {value: [0, "a"], done:false}
(iterator.next()); // {value: [0, "a"], done:false}
var iterator2 = ();
(iterator); // Array Iterator {}
(iterator.next()); // {value: 0, done: false}
(iterator.next()); // {value: 1, done: false}
(iterator.next()); // {value: 2, done: false}
//数组默认的遍历器对象
for(let x of arr[]()){
console.log(x);
}
// for of调用()返回的遍历对象
for(let x of ()){
console.log(x);
}
// for of调用()返回的遍历对象
for(let [index,value] of ()){
console.log(index,value);
}
console.log(()===()); //false
()返回新的遍历对象,它包含了数组每个索引的键值对
()返回新的遍历对象,它包含数组中每个索引的键
扩展运算符(…)也可以将某些数据结构转为数组。
[...[1,2,3]] //[1,2,3]
[...('div')] // NodeList对象转换为Array实例
扩展运算符背后调用的是遍历器接口(),如果一个对象没有部署这个接口,就无法转换。扩展运算符调用对象的遍历器方法,进行遍历。
let arr2=['a','b','c'];
var iterator=arr2.entries();
console.log([...iterator]);
图片