前言

这是我梳理JavaScript根底系列文章中的一篇,这里没有谈及各类循环的效率,次要是总结一下应用形式和理解一些注意事项,点击二三级题目能够关上MDN相应文档,日常博客记录在语雀,欢送关注 语雀文档。

如果文章对你有帮忙的话,欢送点赞评论珍藏加转发。有问题和纳闷的话也能够在评论区留言,我会第一工夫回复大家,如果感觉我的文章哪里有知识点谬误的话,也恳请可能告知,把错的货色了解成对的,无论在什么行业,都是致命的。

JavaScript中循环

  1. for
  2. for...of
  3. for...in
  4. for await...of
  5. forEach 这个其实不能划为此类
  6. while
  7. 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

纯正的forJavaScript中最根底的循环语句

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']enumerablefalse所有没有被遍历进去,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

JavaScriptArray、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

  1. forEach办法按升序为数组中含有效值的每一项执行一次 callback 函数;
  2. forEach不会扭转原数组,然而能够被callback 批改;
  3. forEach不可链式调用;
  4. forEach遍历的范畴在第一次调用 callback 前就会确定;
  5. 除了抛出异样以外,没有方法停止或跳出 forEach循环;
  6. 如果曾经存在的值被扭转, callback 拿到的是最新的值;
  7. 调用 forEach 后增加到数组中的项不会被 callback 拜访到;
  8. 已删除的项不会被遍历到。如果已拜访的元素在迭代时被删除了(例如应用 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异同

  1. 相同点

    • for...infor...of语句都是循环(迭代)一些货色;
    • 都能够 break,continue return中断遍历。
  2. 不同点

    • 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.forEachf()外部的一个办法,在array.forEachreturn和在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...inreturn能失常中断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...ofreturn能失常中断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) //无奈打印,曾经停止

在函数外部或全局作用域应用forreturn能失常中断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) //无奈打印,曾经中止执行 

在函数外部或全局作用域应用whiledo...whilereturn能失常中断whiledo...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) 

小结:

  1. return会将此时进行的语句进行,然而return更加实用于函数语句;
  2. 对于forEach办法,除抛出异样外无奈中断,本节前面不再对forEach进行举例。

break

break语句停止以后循环、switch语句或label 语句( label 语句,前面专门写一篇文章),并把程序控制流转到紧接着被停止语句前面的语句。

在函数外部或全局作用域应用for...inbreak能失常中断以后循环,但不会阻止后续程序执行。

// 在函数中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...ofbreak能失常中断以后循环,但不会阻止后续程序执行。

// 在函数中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

在函数外部或全局作用域应用forbreak能失常中断以后循环,但不会阻止后续程序执行。

// 在函数中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

在函数外部或全局作用域应用whiledo...whilebreak能失常中断以后循环,但不会阻止后续程序执行。

// 在函数中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...incontinue能失常跳过本次循环,持续下一次循环。

// 在函数中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...ofcontinue失常跳过本次循环,持续下一次循环。

// 在函数中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

在函数外部或全局作用域应用whiledo...whilecontinue跳过本次循环,持续下一次循环。

// 在函数中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用于跳过本次循环,持续下一次循环。

总结

  1. forEach除了抛出异样,否则无奈中断;
  2. 三者都会将此时进行的语句进行/跳过;
  3. break中断以后循环,但不会阻止后续程序执行;
  4. continue跳过本次循环,持续下一次循环;
  5. return是函数返回语句,然而返回的同时也将函数进行;
  6. 应用的语句环境不一样,breakcontinue是用在循环或switch语句中,return是用在函数语句中。

援用

首发于语雀文档@is_tao
MDN
js中的break,continue和return到底怎么用?