谈一下Javascript的几种for循环
文章目录

一.for循环
for循环,我们最常见的循环
var arr = [2, 3, 45, 6];
for (var i = 0; i < arr.length; i++) {
var a = arr[i];
}
for循环一般形式为:for (表达式1; 表达式2; 表达式3) { 循环体;}
执行顺序: 表达式1,表达式2,循环体,表达式3
1.优点
- 程序简洁,结构清晰,循环初始化,循环变量化,循环体和循环条件位置突出
- 可以使用break关键字,终止并跳出循环
- 可以使用continue关键字,跳过本次循环
2.缺点
- 只能遍历数组,无法遍历对象(如果想遍历对象,可以使用
Object.keys()
转化之后再遍历) - 需要跟踪计数器和退出条件,结构稍显复杂
二.forEach循环
参数是个回调函数,此回调函数三个参数:第一个是value,第二个是index,第三个是数组体
var arr = [2, 3, 45, 6];
arr.forEach((value, index, array) => {
console.log(value);
console.log(index);
console.log(array);
});
1.优点
- 遍历的时候更加简洁,效率和for循环相同,不用关心下标的问题
2.缺点
- 不能跳出循环,如break和return
- 也不能略过循环 ,如使用continue,可以使用return 当做continue使用
- 只能循环数组
forEach遍历是另一种形式的 JavaScript 循环。但是,forEach()实际上是数组方法,因此只能用在数组中。也无法停止或退出 forEach 循环。如果希望你的循环中出现这种行为,则需要使用基本的 for 循环。
三.for… in循环
for…in循环实际是为循环可枚举对象而设定的
特点:for....in循环返回值是数据结构的 键值,也就是遍历对象时返回该对象的key值,遍历数组返回的数组的下标
一般使用for…in来遍历对象,当然,数组也可以,只不过不推荐遍历数组.
遍历数组时,index遍历出的是数组的下标:
var arr = [2, 3, 45, 6];
for (var index in arr) { // 不推荐这样
console.log(index);
console.log(arr[index]);
}
遍历对象时,index遍历出的是对象的key值
var obj = {
a: 1,
b: 3,
c: 35
}
for (var index in obj) {
console.log(index);
}
为什么说不推荐使用for…in循环数组呢?因为for…in循环是访问所有可枚举属性,就意味着,如果向Array的prototype中添加某方法,或者其他属性,这些属性或方法都会被循环出来.
Array.prototype.abc = 123;
Array.prototype.decimalfy = function () {
for (let i = 0; i < this.length; i++) {
this[i] = this[i].toFixed(2);
}
};
var arr = [2, 3, 45, 6];
for (var index in arr) { // 不推荐这样
console.log(arr[index]);
}
//最后打印结果除了原数组中的值之外,还多了另外2个东西
这就是为何在循环访问数组时,不建议使用 for…in 循环。
1.优点
- 非常适合遍历对象
- 可以遍历数组的键名,遍历对象简洁方便
2.缺点
- 遍历数组时,会将手动添加到Array.prototype的属性和方法给遍历出来
- fot in循环里面的index是string类型的,可能会多些隐式转换的开销
- 通过for-in循环输出的属性名的顺序是不可预测的,所有属性都会被返回一次,但是返回的顺序因浏览器不同。
四.for…of循环
ES6新加的一种循环方法.既比传统的for循环简洁,同时弥补了forEach和for…in循环的短板
for...of 循环用于循环访问任何可迭代的数据类型。
原生具备 Iterator 接口的数据结构如下。
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象
1.for…of遍历数组
var arr = [2, 3, 45, 6];
for (var value of arr) {
console.log(value);// 2,3,45,6
}
for...of
循环直接读取键值.如果要通过for...of
循环,获取数组的索引,可以借助数组实例的entries
方法和keys
方法
2.for…of遍历字符串
let iterable = "中国人";
for (let value of iterable) {
console.log(value);
}
// "中"
// "国"
// "人"
3.for…of遍历Map
let iterable = new Map([["a", 1], ["b", 2], ["c", 3]]);
for (let [key, value] of iterable) {
console.log(value);
}
// 1
// 2
// 3
for (let entry of iterable) {
console.log(entry);
}
// [a, 1]
// [b, 2]
// [c, 3]
4.for…of遍历Set
let iterable = new Set([1, 1, 2, 2, 3, 3]);
for (let value of iterable) {
console.log(value);
}
// 1
// 2
// 3
5.for…of循环遍历DOM集合
并不是所有类似数组的对象都具有 Iterator 接口,一个简便的解决方法,就是使用
Array.from
方法将其转为数组。
let nodeList=document.querySelectorAll('ul>li');
for (let node of nodeList) {
node.classList.add("read");
}
6.for…of循环遍历arguments
// arguments对象
function printArgs() {
for (let x of arguments) {
console.log(x);
}
}
printArgs('a', 'b');
// 'a'
// 'b'
1.优点
- 避免了for…in的所有缺点,可以使用break,continue和return
- 支持数组的遍历,还支持类数组(伪数组),和字符串的遍历
- 支持Map,和Set对象遍历
2.缺点
- 不适用于处理原有的原生对象
- for…of 不能循环普通的对象,需要通过和
Object.keys()
搭配使用 - 不会遍历出动态添加的属性.也就是在运动过程中动态创建的对象
为什么说for...of
不能遍历普通的对象呢?
var obj = {
a: 1,
b: 3,
c: 35
}
for (let value of obj) {
console.log(value);//obj is not iterable
}
这段代码会报错,obj is not iterable
,说对象不是一个可迭代器,那其根本原因就是普通对象上面没有部署Symbol.iterator
这个迭代器,而数组之所以能遍历,却是数组已经部署了Symbol.iterator
这个迭代器,Symbol(Symbol.iterator)
的值为该数组的generator
函数
五.提高for循环性能要点
- 适时加break,不需要遍历全部的就要加跳出条件
- 不要在for循环体里声明变量(建议一次var,多次赋值),为了防止var会有声明提升,还是尽量还是使用let吧
- 数组长度缓存,避免每次执行都去计算下length长度