本文针对 javascript 和 es6 的循环方法做了如下整理工作:1)整理了和 for 相关的循环,如 for循环、for...in、for...of , 2)整理了仅用于数组中的较常见的循环方法,如 map、forEach、filter、reduce,欢迎讨论!
一、for 循环:索引遍历
var arr = [1, 2, 3];
for(let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
二、for...in 循环:对象专用,只能索引遍历
var obj = {
a:1,
b:2,
c:3
};
for(let i in obj) {
console.log(i); //键名
console.log(obj[i]); //键值
}
for...in 用来遍历一个对象的全部属性,1)它遍历的是对象所有可遍历的属性,会跳过不可遍历的; 2)不仅遍历对象自身的属性,还遍历继承的属性。
如果只想遍历对象自身的属性,则应该结合使用hasOwnProperty方法,
var obj = {
a:1,
b:2,
c:3
};
for(let i in obj) {
if(obj.hasOwnProperty(i)){ //判断i是不是对象自身的属性
console.log(i); //键名
console.log(obj[i]); //键值
}
}
最后,需要注意,不推荐使用 for...in 遍历数组,因为它还会遍历非数字键!
三、for...of 循环:多种遍历
for...of 是ES6中新增的遍历方法,我们需要先介绍一下 Iterator(遍历器)。Iterator是ES6为了可以处理不同的数据结构,而提出的一种统一的接口机制。任何数据接口,只要部署了Iterator接口,就可以用 for...of 完成遍历操作。
原生具备Iterator接口的数据结构如下:
- 数组、字符串(for...of 在遍历数组时,它的遍历器接口只返回数字索引的属性。)
- Map、Set
- 函数的arguments对象
- DOM NodeList对象
- Generator对象
var arr = [1, 2, 3];
for(let value of arr) {
console.log(value);
}
for...of 默认是键值遍历,而ES6中提供的3个新方法 entries() 、keys() 、values() 专用于遍历数组,可以有多种方式。
var arr = ['a', 'b', 'c'];
for(let i of arr.keys()) { //遍历键名
console.log(i);
} //0 1 2
for(let value of arr.values()) { //遍历键值
console.log(value);
} //a b c
for(let [i, value] of arr.entries()) { //遍历键值对
console.log(i);
console.log(value);
} //0 'a' 1 'b' 2 'c'
四、map():数组专用
map( ) 将数组的所有成员依次传入参数函数,然后把每一次的执行结果组成一个新数组返回,不改变原数组。MDN中对map结构的描述已经很清楚了,这里简单的整理了一下。
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
//callback:生成新数组元素的回调函数,使用三个参数
//currentValue:必须,数组中正在处理的当前成员
//index:可选,当前成员的位置
//array:可选,数组本身
//thisArg:可选,回调函数内部的this指向
}[, thisArg]);
示例:
var arr = [1, 2, 3];
var map_arr = arr.map(function (value) {
return value + 1;
}); //[2, 3, 4]
arr; //[1, 2, 3]
注意,map方法不会跳过undefined和null,但会跳过空位。[1, , 3]
五、forEach():数组专用
forEach() 与map() 相似,也不改变原数组,唯一的区别在于forEach只是操作数据,不会返回值,因此如果数组遍历的目的是为了得到返回值,就用map方法,否则只是为了在屏幕输出内容就使用forEach方法。结构如下:
arr.forEach(callback(currentValue [, index [, array]])[, thisArg]);
//callback:生成新数组元素的回调函数,使用三个参数
//currentValue:必须,数组中正在处理的当前成员
//index:可选,当前成员的位置
//array:可选,数组本身
//thisArg:可选,回调函数内部的this指向
示例:
var arr = [1, 2, 3];
arr.forEach(function (value) {
console.log(value + 1);
});
注意,forEach方法无法中途跳出循环,break和return都无效!如果希望符合某种条件就中断遍历,那么应该使用for循环!
forEach也会跳过数组的空位!
六、filter():数组专用
filter() 用于过滤数组成员,满足条件的成员组成一个新数组返回!不会改变原数组,与map相似。结构如下:
var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
示例:
var arr = [1, 2, 3];
var filter_arr = arr.filter(function (value) {
return value > 1;
}); //[2,3]
七、reduce():数组专用
reduce() 和reduceRight() 依次处理数组的每个成员,最终累计为一个值。
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue]);
//accumulator:累积变量,默认为数组的第一个成员,或initialValue
//currentValue:当前变量,默认为数组的第2个成员
//index:可选,当前位置,如果提供了initialValue,则起始索引号为0,否则从索引1起始。
//initialValue:可选,reduce的第2个参数,作用是对累计变量设定初值,处理空数组时尤其有用!
说明,
1. 如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。
2. 对于空数组,指定reduce的初值更安全,否则可能报错!
八、对比总结
针对数组的遍历,可以使用for、for...of,优先使用for。
针对对象的属性遍历,使用for...in,注意需要结合hasOwnProperty判断是否为自身的属性。
针对数组的操作,
(1)map、forEach、filter方法的内部结构相同,都是回调函数和4个参数,但由于forEach不返回值,因此回调函数不需要return。
(2)map和forEach方法除了是否返回值,其余都相同。
(3)forEach不能中断循环,因此如果需要中途跳出循环时,建议使用for循环。