这篇文章主要是将js中循环的方式进行一个总结,包括常见的循环方式以及需要注意的事项,我尽可能的写的明白一些,因为很多太小的细节可能我自己也不会完全深入的搞明白!
//声明一个密集数组,如果不进行fill填充的话,默认的是一个稀疏型数组
let arr = new Array(9999999).fill(9) //用于测试性能
let tR = [2, 3, 4, 5, 3, 2, 1] //用于测试特性
let i = 0 //for 循环使用
let obj = {
name: 'jim',
[Symbol('sm')]: 800,
get: function () { },
childObj: {},
num: 900,
1: 888,
} //for of 和for in测试特性使用
//测试普通的for循环
console.time('for')
for (let i = 0; i < arr.length; i++) { }
console.timeEnd('for')
//for: 6.968017578125 ms
//测试while循环
console.time('while')
while (i < arr.length) {
i++
}
console.timeEnd('while')
//while: 34.88720703125 ms
//测试for in
console.time('for in')
for (let i in arr) { }
console.timeEnd('for in')
//for in: 2076.422119140625 ms
//测试for of
console.time('for of')
for (let i of arr) { }
console.timeEnd('for of')
//for of: 129.52490234375 ms
//测试foreach
console.time('for each')
arr.forEach(() => { })
console.timeEnd('for each')
//for each: 88.530029296875 ms
/**
== for 循环
+ 可定制化比较强 可以随时break 和 continue 来决定要不要继续循环
+ 判断条件可以随意修改
+ 可以在循环的过程中进行每一项值的修改 也可以改变源数组的数据
- 取值比较麻烦,需要使用数组[下标]的方式进行值的操作
*/
new Promise(res => {
for (; i < tR.length; i++) {
if (i % 2 == 0) {
tR[i] = 'new'
}
}
res()
}).then(() => {
console.log(tR) //['new', 3, 'new', 5, 'new', 2, 'new']
})
/**
== while 循环
+ 循环可以通过判断条件进行终止
+ 判断条件可以随意修改
+ 可以在循环的过程中值不被修改,源数组不会被更改
- 一般适用于不知道循环次数的前提下,使用某一个条件进行终止循环 效率和for差不多,只是不知道循环次数的时候可以使用while
*/
new Promise(res => {
while (i > tR.length) {
i++
// delete(tR[i])
if (i % 2 == 0) {
tR[i] = 'new'
}
}
res()
}).then(() => {
console.log(tR) //[2, 3, 4, 5, 3, 2, 1]
})
/**
== forEach 循环
+ 语法简单
- 遍历的时候无法修改和删除集合数据
- 方法不能使用break,continue语句跳出循环,或者使用return从函数体返回,对于空数组不会执行回调函数
*/
new Promise(res => {
tR.forEach((v, i, a) => {
//i不会被改变
i = i + Number(v)
if (i % 2 == 0) {
return
}
if (v == 2) {
//可以在判断条件里面执行业务逻辑,但是数据没办法传递出去
console.log(v) // 2
console.log(a) //[2, 3, 4, 5, 3, 2, 1]
}
//不会被终止,源数组不会被改变
})
res()
}).then(() => {
console.log(i) //0
})
// 源数组不会被改变
new Promise(res => {
tR.forEach((v, i, a) => {
delete (v % 2 == 0)
})
res()
}).then((a) => {
console.log(tR) //[2, 3, 4, 5, 3, 2, 1]
})
/**
== for in 循环
+ 语法简单
+ 可以用来遍历对象
- 遍历的时候无法修改和删除集合数据
- 方法不能使用break,continue语句跳出循环,或者使用return从函数体返回,对于空数组不会执行回调函数
*/
//可以改变源数组 删除数组
let pro = new Promise((res => {
for (let v in tR) {
delete (tR[v])
}
res()
}))
p.then(r => {
console.log(tR) //稀疏数组 [length = 7]
})
//遍历数组
new Promise(res => {
for (let v in tR) {
i = i + tR[v]
}
res()
}).then(() => {
console.log(i) //20
})
//遍历对象需要注意的点
Object.prototype.fn = function fn() { } //公有属性 函数
Object.prototype.O = 'obj' //公有属性string
// 数字->string->function->对象->number 但是遍历不到Symbol 属性 同时会将公有属性遍历出来
for (let k in obj) {
console.log(obj[k])
/**
ceshi.html:158 888
ceshi.html:158 jim
ceshi.html:158 ƒ () { }
ceshi.html:158 {}
ceshi.html:158 900
ceshi.html:158 ƒ fn() { }
ceshi.html:158 obj
*/
}
for (let k in obj) {
//将非私有属性 过滤掉
if (obj.hasOwnProperty(k)) {
console.table(obj[k])
}
/**
ceshi.html:169 888
ceshi.html:169 jim
ceshi.html:169 function () { }
ceshi.html:169
ceshi.html:169 900
*/
}
//获取symbol属性
console.log(Object.getOwnPropertySymbols(obj)) //[Symbol(sm)]
/**
== for of 循环
+ 语法简单
- 遍历的时候无法修改和删除集合数据
- 方法不能使用break,continue语句跳出循环,或者使用return从函数体返回,对于空数组不会执行回调函数
原理是 查看属性中有没有symbol.iterator迭代器 也就是说我们可以通过改变Symbol的规则 进行更改遍历的结果输出 代码如下
*/
//删除数组 不改变源数组
new Promise(res => {
for (let v of tR) {
delete (v % 2 == 0)
}
res()
}).then(() => {
console.log(tR) //[2, 3, 4, 5, 3, 2, 1]
})
//遍历数组
new Promise(res => {
for (let v of tR) {
i = i + v
}
res()
}).then(() => {
console.log(i) //20
})
//使用for of 遍历类数组 给对象添加iterator的属性
let O = {
0: 1,
1: 2,
2: 3,
length: 3 //不添加lenth属性的话,不算一个类数组
}
O[Symbol.iterator] = Array.prototype[Symbol.iterator]
for (let v of O) {
console.log(v) //1、2、3
}
// 重写iterator方式 既然for of 是根据iterator规则来的,那么我们就可以重写他的规则进行满足我们的业务需求
tR[Symbol.iterator] = () => {
let i = 0
return {
//每一个iterator都必须有一个next函数,他执行次数多少是根据done来判断的,true的时候就不执行了,否则一直执行
next() {
// i++
//这里我们改变他的遍历次数
i += 2
if (i > tR.length - 1) {
return {
done: true,
value: null
}
} else {
return {
done: false,
value: tR[i]
}
}
}
}
}
for (let k of tR) {
console.log(k) // 4、3、1
}
这篇文章不是水的,其实是我最近想将js中的一些基础知识也总结一下,这样晚上一下我的知识体系,也重温一下之前漏掉的一些细节,这样做的一个目的是巩固自己的基础,不至于在一些很简单的问题上浪费时间,比如我们写代码的时候,使用for in 进行对象的遍历,突然发现莫名其妙多了属性,那么这个时候你就要检查一下是不是别的同事写了一些Object的公共属性进去,自己也没有进行过滤导致的,诸如此类,所以可能这些总结每一个点都不难,但是系统起来就并非易事,还是脚踏实地的慢慢琢磨!拜了个白