前言
这是我梳理JavaScript根底系列文章中的一篇,这里没有谈及各类循环的效率,次要是总结一下应用形式和理解一些注意事项,点击二三级题目能够关上MDN相应文档,日常博客记录在语雀,欢送关注 语雀文档。
如果文章对你有帮忙的话,欢送点赞评论珍藏加转发。有问题和纳闷的话也能够在评论区留言,我会第一工夫回复大家,如果感觉我的文章哪里有知识点谬误的话,也恳请可能告知,把错的货色了解成对的,无论在什么行业,都是致命的。
JavaScript中循环
for
for...of
for...in
for await...of
forEach
这个其实不能划为此类while
do...while
先创立根底数据,全文通用。
const string='12345'const array = [1, 2, 3, 4, 5]const uint8Array=new Uint8Array([0, 1, 2, 3])const searchParams = new URLSearchParams("key1=value1&key2=value2");const obj = { 'obj0': 1, 'obj1': 2, 'obj2': 3, 'obj3': 4, 'obj4': 5}const obj2 = Object.defineProperties({ 'obj0': 1}, { 'obj1': { value: 2, enumerable: true }, 'obj2': { value: 3, enumerable: true }, 'obj3': { value: 4, enumerable: false },});obj2.__proto__.obj4=5const map = new Map([[0,1],[1,2],[2,3],[3,4],[4,5]])const set = new Set([1,2,3,4,5])
for
纯正的for
是JavaScript
中最根底的循环语句
for (let i = 0; i < array.length; i++) { console.log(map.get(i)); //循环输入1 2 3 4 5}
须要晓得的是,for
的三个表达式都是可选的,也就是下面的let i = 0; i < array.length; i++
这部分,然而,尽管表达式是可选的,但三个;
是强制要求要有的。
for (let i = 0,j=0; ; i++,j++) { //这里不给他停止,会gg的 if (i > array.length) break; console.log(i,j);}// 0 0// 1 1// 2 2// 3 3// 4 4// 5 5
如果你有需要的话,你甚至能够申明一个无语句的for
循环,这样也是能够的。
let j=[]for (let i = 0; i < array.length; i++,j.push(i)); //这个分号不能少console.log(j) //[ 1, 2, 3, 4, 5 ]
for...of
for...of
语句循环可迭代对象(包含 Array,Map,Set,String,TypedArray,arguments
对象等等),循环进去的的对象的值。
for (const element of array) { console.log(element);//循环输入1 2 3 4 5}
这里要留神,一般的object
对象不是可迭代对象,无奈应用for...of
,
for (let element of obj) { console.log(element); // TypeError: obj is not iterable}
甚至能够循环字符串
for (let element of string) { console.log(element); //循环输入1 2 3 4 5}
也能循环Map和Set
for (let element of map) { //是个数组哟 console.log(element[0],element[1]); // 0 1 // 1 2 // 2 3 // 3 4 // 4 5}for (let element of set) { console.log(element); //循环输入1 2 3 4 5}
对于for...of
的循环,能够由break、throw、continue、return
终止。
for (let element of set) { if(element>3) break console.log(element); //循环输入1 2 3}
对于不反对的一般object
,咱们能够为他创立一个迭代器,这样也能实现for...of
循环。
obj[Symbol.iterator] = function*(){ var keys = Object.keys(obj); for(var key of keys){ yield [key,obj[key]] }};for(var [key,value] of obj){ console.log(key,value); // obj0 1 // obj1 2 // obj2 3 // obj3 4 // obj4 5}
也能借助Object.entries 实现遍历,Object.entries()
办法返回一个给定对象本身可枚举属性的键值对数组。
for (const [key, value] of Object.entries(obj2)) { console.log(`${key}: ${value}`); //obj0: 1 //obj1: 2 //obj2: 3}
还有一些其余可迭代对象能够应用for...of
,这里就不一一举例了。
for...in
for...in
语句以任意程序遍历一个对象的除Symbol以外的可枚举属性,包含继承的可枚举属性,留神:语句无奈保障遍历程序(各浏览器有点区别,也能够去理解下惯例属性和排序属性)。
for (let prop in obj) { console.log(prop + " = " + obj[prop]); // obj0 = 1 // obj1 = 2 // obj2 = 3 // obj3 = 4 // obj4 = 5}
只会遍历出可迭代的属性,obj2['obj3']
的enumerable
为false
所有没有被遍历进去,obj2['obj4']
是继承过去的属性(__proto__
下面的),也是能遍历进去的。
for (let prop in obj2) { console.log(prop + " = " + obj2[prop]); // obj0 = 1 // obj1 = 2 // obj2 = 3 // obj4 = 5}
如果仅需本身属性,能够应用hasOwnProperty判断
for (let prop in obj2) { if (obj2.hasOwnProperty(prop)) { console.log(prop + " = " + obj[prop]); } // obj0 = 1 // obj1 = 2 // obj2 = 3}
for await...of
和for...fo
一样,但它只实用于异步可迭代的异步迭代器。
function getRes(){ return fetch('http://whois.pconline.com.cn/ip.jsp') .then(response => 'res')}async function test(){ let i=0 let arr = [getRes(),getRes(),getRes()] for await (let x of arr){ i++ console.log(x+'---'+i); //按程序循环出 res---1 res---2 res---3 }}test()
异步生成器曾经实现了异步迭代器协定, 所以能够用 for await...of
循环。
async function* asyncGenerator() { let i = 0; while (i < 3) { yield i++; }}async function test(){ for await (num of asyncGenerator()) { if (num>1) break; //也能应用break停止 ,齐全和for...of一样 console.log(num); //按程序循环出 0 0 }}test()
while
while
语句能够在某个条件表达式为真的前提下,循环执行指定的一段代码,直到那个表达式不为真时完结循环。
let n=0while (n < array.length) { console.log(array[n]); //循环输入1 2 3 4 5 n++;}
do...while
do...while
语句创立一个执行指定语句的循环,直到条件值为 false
。在执行后do
内的代码后,检测while
内的条件,所以do
内代码至多会执行一次。
let n=0do { console.log(array[n]); //循环输入1 2 3 4 5 n++;}while (n < array.length) do { console.log(array[n]); //1 至多会循环一次 n++;}while (n < 0)
forEach
JavaScript
中Array、Map、Set、NodeList、TypedArray、URLSearchParams
都存在forEach
办法,对上述类型的每个元素执行一次给定的函数,无返回值。除URLSearchParams
外,其余都有第二个thisArg可选参数,在Map.prototype.forEach
中有示例。
Map.prototype.forEach
map.forEach((value,key,myMap)=>{ console.log(`${key}-${value}-${myMap.get(key)}`) // 0-1-1 // 1-2-2 // 2-3-3 // 3-4-4 // 4-5-5})//第二个参数,本文后续类型的不再举例,这里不能应用箭头函数//如果应用箭头函数表达式来传入函数参数, thisArg 参数会被疏忽,因为箭头函数在词法上绑定了 this 值。map.forEach(function(value,key,myMap){ console.log(`${key}-${value}-${myMap.get(key)}-${this.exp}`) // 0-1-1-exp // 1-2-2-exp // 2-3-3-exp // 3-4-4-exp // 4-5-5-exp},{exp:'exp'})
Array.prototype.forEach
forEach
办法按升序为数组中含有效值的每一项执行一次callback
函数;forEach
不会扭转原数组,然而能够被callback 批改;forEach
不可链式调用;forEach
遍历的范畴在第一次调用callback
前就会确定;- 除了抛出异样以外,没有方法停止或跳出
forEach
循环; - 如果曾经存在的值被扭转,
callback
拿到的是最新的值; - 调用
forEach
后增加到数组中的项不会被callback
拜访到; - 已删除的项不会被遍历到。如果已拜访的元素在迭代时被删除了(例如应用
shift
),之后的元素将被跳过。
array.forEach((currentValue, index ,myArray)=> { console.log(`${currentValue}-${index}-${myArray[index]}`); // 1-0-1 // 2-1-2 // 3-2-3 // 4-3-4 // 5-4-5});
forEach
遍历的范畴在第一次调用 callback
前就会确定。调用 forEach
后增加到数组中的项不会被 callback
拜访到。如果曾经存在的值被扭转,则传递给 callback
的值是 forEach
(遍历到他们那一刻的值。已删除的项不会被遍历到。如果已拜访的元素在迭代时被删除了(例如应用 shift
),之后的元素将被跳过。
array.forEach((currentValue) => { if (currentValue === 1) { //曾经存在的值被扭转,则传递给 callback 的值是 forEach() 遍历到他们那一刻的值 array[4] = 666 //不会遍历进去,forEach遍历的范畴在第一次调用 callback 前就会确定 array.push(777) } console.log(currentValue) // 1 2 3 4 666});array.forEach((currentValue) => { if (currentValue === 1) { array.shift(); } //执行到1的时候,此时currentValue曾经是1了,所以能够打印进去,把数组第一个删除,导致 //所有数组向前后退了一步[2,3,4,5],然而此时,索引曾经是1了,所以跳过了2 打印3 4 5 console.log(currentValue) // 1 // 3 // 4 // 5});
除了抛出异样以外,没有方法停止或跳出 forEach()
循环
array.forEach((currentValue)=> { if(currentValue>3) break; // Uncaught SyntaxError: Illegal break statement console.log(currentValue)});
扁平化数组能够看看我的这篇文章
Set.prototype.forEach
set.forEach((value,mySet)=>{ console.log(`${value}-${mySet}`) // 1-1 // 2-2 // 3-3 // 4-4 // 5-5})
NodeList.prototype.forEach
let node = document.createElement("div");let kid1 = document.createElement("p");let kid2 = document.createTextNode("hey");let kid3 = document.createElement("span");node.appendChild(kid1);node.appendChild(kid2);node.appendChild(kid3);let list = node.childNodes;list.forEach((currentValue, currentIndex, listObj) => { console.log(`${currentValue}-${currentIndex}-${listObj[currentIndex]}`) // [object HTMLParagraphElement]-0-[object HTMLParagraphElement] // [object Text]-1- [object Text] // [object HTMLSpanElement]-2- [object HTMLSpanElement] });
TypedArray.prototype.forEach
TypedArray一个类型化数组
uint8Array.forEach((element, index, array)=>{ console.log(`${element}-${index}-${array[index]}`) // 0-0-0 // 1-1-1 // 2-2-2 // 3-3-3});
URLSearchParams.forEach
searchParams.forEach((value, key,searchParams)=> { console.log(value, key,searchParams.get(key)); // value1 key1 value1 // value2 key2 value2});
for...of和for...in异同
相同点
for...in
和for...of
语句都是循环(迭代)一些货色;- 都能够
break,continue
和return
中断遍历。
不同点
for...in
语句以任意程序遍历一个对象的除Symbol
以外的可枚举属性,包含继承的可枚举属性,留神:语句无奈保障遍历程序;for...in
迭代的是对象的键,而for...of
则迭代对象的键对应的值;for...in
能够迭代任何对象,但for...of
则须要对象是可迭代对象;;
do...while和while异同
相同点:都是循环语句
不同点:do...while
至多会循环一次
JavaScript中的break,continue和return
return
return语句终止函数执行( return
是函数返回语句,然而返回的同时也将函数进行),并返回一个指定的值给函数调用者,如果疏忽,则返回 undefined
。
array.forEach
是f()
外部的一个办法,在array.forEach
内return
和在f()
办法内return
是不一样的。
// 在函数中function f() { array.forEach((item)=>{ console.log(item) // return有效 间断打印 1 2 3 4 5 return item+1 //array.forEach是无返回值的 }) console.log(2) //打印2}console.log(f()) //undefined//在全局作用域array.forEach((item)=>{ console.log(item) return item+1 // return有效 间断打印 1 2 3 4 5}) console.log(3) //打印3
在函数外部或全局作用域应用for...in
,return
能失常中断for...in
语句执行
// 在函数中function f() { for (const objElement in array) { console.log(array[objElement]) //1 return array[objElement] } console.log(2) //无奈打印,曾经停止函数执行}console.log(f()) //1// 在全局作用域for (const objElement in array) { console.log(array[objElement]) //1 return array[objElement]}console.log(3) //无奈打印,曾经停止
在函数外部或全局作用域应用for...of
,return
能失常中断for...of
语句执行
// 在函数中function f() { for (const objElement of array) { console.log(objElement) //1 return objElement } console.log(2) //无奈打印,曾经停止函数执行}console.log(f()) //1// 在全局作用域for (const objElement of array) { console.log(objElement) //1 return objElement}console.log(3) //无奈打印,曾经停止
在函数外部或全局作用域应用for
,return
能失常中断for
语句执行
// 在函数中function f() { for (let i = 0; i < array.length; i++) { console.log(array[i]) // 1 return array[i] } console.log(2) //无奈打印,曾经停止函数执行}console.log(f()) //1// 在全局作用域for (let i = 0; i < array.length; i++) { console.log(array[i]) // node环境和v8 体现不统一 Illegal return statement return array[i]}console.log(3) //无奈打印,曾经中止执行
在函数外部或全局作用域应用while
和do...while
,return
能失常中断while
和do...while
语句执行
// 在函数中function f() { let n=0 while (n < array.length) { n++; if (n === 3) { return 'f'; } console.log(n) // 1 2 } console.log(2) //2}console.log(f()) //f//在全局作用域let n=0while (n < array.length) { n++; if (n === 3) { return 'f'; // Illegal return statement } console.log(n) }console.log(3)
小结:
return
会将此时进行的语句进行,然而return
更加实用于函数语句;- 对于
forEach
办法,除抛出异样外无奈中断,本节前面不再对forEach
进行举例。
break
break语句停止以后循环、switch语句或label 语句( label
语句,前面专门写一篇文章),并把程序控制流转到紧接着被停止语句前面的语句。
在函数外部或全局作用域应用for...in
,break
能失常中断以后循环,但不会阻止后续程序执行。
// 在函数中function f() { for (const objElement in array) { console.log(array[objElement]) //1 break } console.log(2) //2}//console.log(f()) //undefined// // 在全局作用域for (const objElement in array) { console.log(array[objElement]) //1 break}console.log(3) //3
在函数外部或全局作用域应用for...of
,break
能失常中断以后循环,但不会阻止后续程序执行。
// 在函数中function f() { for (const objElement of array) { console.log(objElement) //1 break } console.log(2) //2}//console.log(f()) //undefined// // 在全局作用域for (const objElement of array) { console.log(objElement) //1 break}console.log(3) //3
在函数外部或全局作用域应用for
,break
能失常中断以后循环,但不会阻止后续程序执行。
// 在函数中function f() { for (let i = 0; i < array.length; i++) { console.log(array[i]) // 1 break; } console.log(2) //2}//console.log(f()) //undefined// // 在全局作用域for (let i = 0; i < array.length; i++) { console.log(array[i]) // 1 break;}console.log(3) //3
在函数外部或全局作用域应用while
和do...while
,break
能失常中断以后循环,但不会阻止后续程序执行。
// 在函数中function f() { let n=0 while (n < array.length) { n++; if (n === 3) { break; } console.log(n) // 1 2 } console.log(2) //2}console.log(f()) //undefined//在全局作用域let n=0while (n < array.length) { n++; if (n === 3) { break; } console.log(n) // 1 2}console.log(3) //3
小结:break
终止以后循环,但不会阻止后续程序执行;
continue
continue
跳过本次循环,持续下一次循环。
// 在函数中function f() { for (let i = 0; i < array.length; i++) { if(array[i] === 1) continue; console.log(array[i]) // 2 3 4 5 } console.log(2) //2}console.log(f()) //undefined//在全局作用域for (let i = 0; i < array.length; i++) { if(array[i] === 1) continue; console.log(array[i]) // 2 3 4 5}console.log(3) //3
在函数外部或全局作用域应用for...in
,continue
能失常跳过本次循环,持续下一次循环。
// 在函数中function f() { for (const objElement in array) { if(array[objElement] === 1) continue; console.log(array[objElement]) // 2 3 4 5 } console.log(2) //2}console.log(f()) //undefined//在全局作用域for (const objElement in array) { if(array[objElement] === 1) continue; console.log(array[objElement]) // 2 3 4 5}console.log(3) //3
在函数外部或全局作用域应用for...of
,continue
失常跳过本次循环,持续下一次循环。
// 在函数中function f() { for (const objElement of array) { if(objElement === 1) continue; console.log(objElement) // 2 3 4 5 } console.log(2) //2}console.log(f()) //undefined//在全局作用域for (const objElement of array) { if(objElement === 1) continue; console.log(objElement) // 2 3 4 5}console.log(3) //3
在函数外部或全局作用域应用while
和do...while
,continue
跳过本次循环,持续下一次循环。
// 在函数中function f() { let n=0 while (n < array.length) { n++; if (n === 3) { continue; } console.log(n) // 1 2 4 5 } console.log(2) //2}console.log(f()) //undefined//在全局作用域let n=0while (n < array.length) { n++; if (n === 3) { continue; } console.log(n) // 1 2 4 5}console.log(3) //3
小结:continue
用于跳过本次循环,持续下一次循环。
总结
forEach
除了抛出异样,否则无奈中断;- 三者都会将此时进行的语句进行/跳过;
break
中断以后循环,但不会阻止后续程序执行;continue
跳过本次循环,持续下一次循环;return
是函数返回语句,然而返回的同时也将函数进行;- 应用的语句环境不一样,
break
和continue
是用在循环或switch
语句中,return
是用在函数语句中。
援用
首发于语雀文档@is_tao
MDN
js中的break,continue和return到底怎么用?