【JavaScript】循环遍历大赏

🛫 导读

需求

一直以来,对js的循环一知半解,代码写着写着就出问题了,然后各种查资料,解决这类基础问题。今天花大功夫查了各种资料,小结一二,让js的循环遍历清晰一点。

为了少写点代码,将打印输出console.log赋值给了全局变量log,加快敲代码的速度。
var log = console.log

开发环境

版本号描述
文章日期2022-11-26
操作系统Ubuntu 20.04.4 LTSCSDN开发云
node -vv16.17.0npm -v (8.15.0)
Cloud IDE1.71.0

1️⃣ 通用语法类

在讲循环的之前,先知道一下循环结构的执行步骤 
  1、声明循环变量;
  2、判断循环条件;
  3、执行循环体操作;
  4、更新循环变量;
  5、然后循环执行2-4,直到条件不成立,跳出循环。

本分类,在各个编程语言中都比较常见,不涉及具体的操作对象。

while循环

while循环()中的表达式,运算结果可以是各种类型,但是最终都会转为真假,转换规则如下。示例:

function while循环() {
    var num = 1; // 1、声明循环变量

    while (num <= 10) { // 2、判断循环条件;
        log(num + "<br />"); // 3、执行循环体操作;
        num++; // 4、更新循环变量;
    }
}
// while循环()

do-while循环

while循环特点:先判断后执行;
do-while循环特点:先执行再判断,即使初始条件不成立,do-while循环至少执行一次;示例:

function do_while循环() {
    var num = 10;

    do {
        log(num + "<br />"); // 10 9 8 7 6 5 4 3 2 1 0
        num--;
    } while (num >= 0);

    log(num); // -1
}
// do_while循环()

for循环

for循环
  1、for有三个表达式:①声明循环变量;②判断循环条件;③更新循环变量;
    三个表达式之间,用;分割,for循环三个表达式都可以省略,但是两个“;”缺一不可。
  2、for循环的执行特点:先判断再执行,与while相同
  3、for循环三个表达式都可以有多部分组成,第二部分多个判断条件用&& ||连接,第一三部分用逗号分割;
示例:

function for循环() {
    for (var num = 1; num <= 10; num++) {
        log(num + " <br />"); // 1 2 3 4 5 6 7 8 9 10
    }
}
// for循环()

2️⃣ 数组

数组作为JavaScript中最常用的类型,除了上面通用的遍历方式,还支持各种类型的遍历。

for…of

不需要索引的情况,直接使用for...of,代码高效明了。
示例:

function for_of_数组() {
    var arr = ['a', 'b', 'c', 'd'];

    for (let a of arr) {
        console.log(a); // a b c d
    }
}
// for_of_数组()

for…in

for...in本质是获取对象的key(键),数组作为特殊的对象,key就是下标(索引),所以遍历出来的是key,通过数组对象访问key可以获得value。
示例:


    var arr = ['a', 'b', 'c', 'd'];

    for (let a in arr) {
        log(a); // 0 1 2 3
        log(arr[a]); // a b c d
    }

方法forEach

网上说forEach是语法糖(未深究),从实现上其实就是数组对象的一个原型方法。
接收一个函数参数,该函数中接受三个参数,原型为forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void;。通常传递一个参数即可。
示例:

function forEach数组循环() {
    const arr = [1, 2, 3, 4, 5]
    let sum = 0
    arr.forEach(element => {
        log(element)
        sum += element
    })
    log(sum) // 15

    // Array.prototype.forEach.call(arr,function(el){ });
    sum = 0
    Array.prototype.forEach.call(arr, function(el) {
        sum += el;
    });
    log(sum) // 15
}
// forEach数组循环()

方法map、filter、reduce

作为数组常用而且容易混淆的三个方法,列出了其功能描述和示例。
示例:

function map循环() {
    // map循环
    //      遍历时可以返回一个新数组,新数组的结果是原数组中每个元素都调用一次提供的函数后返回的值。
    var arr = [1, 2, 3]
    let newArr = arr.map((item) => item * 2)
    log(newArr); //[2,4,6]
    
    // filter
    var arr = [1, 2, 3]
    let newArr2 = arr.filter((item) => item % 2)
    log(newArr2); //[2,4,6]
    
    // reduce
    // 功能:它用于把一个函数作用在这个 Array 的每一个元素上,然后把结果继续和序列的下一个元素做累积计算。
    // 参数:接受一个函数作为其参数,该函数要求有两个参数,第一个参数用于保存当前累积计算的值,第二个参数则是当前的数组元素。
    var arr = [1, 2, 3]
    let total = arr.reduce((value, item) => {
        log(value, item)
        // 实际就是 1 + 2 + 3
        // return value + item // 6
        // 实际就是 1 - 2 - 3
        // return value - item // -4
        // 实际就是 1 * 2 * 3
        return value * item // 6
    })
    log(total);
}
// map循环()

3️⃣ 对象

for…in

遍历对象,最常用的就是for...in,遍历到对象的key,根据key获取value。
示例:

function for_in循环() {
    // 声明一个Peson类
    function Person() {
        this.name = "张三";
        this.age = 14;
        this.func1 = function () {}
    }
    // 实例化这个类
    var zhangsan = new Person();
    // 使用for-in遍历这个对象
    for (let key in zhangsan) {
        log(zhangsan[key])
    }
}
// for_in循环()

Object.keys

Object.keys获取对象所有属性的名字数组,有了数组,可以参考之前的四种方式进行对象的遍历。
示例:

function 对象循环() {
    // 声明一个Peson类
    function Person() {
        this.name = "张三";
        this.age = 14;
        this.func1 = function () {}
    }
    // 实例化这个类
    var zhangsan = new Person();

    // 使用Object.keys遍历这个对象
    for (let key of Object.keys(zhangsan)) {
        log(key, zhangsan[key])
    }
}
对象循环()

Object.values

很少用到这个方式,不需要获取key的情况下使用。
示例:

function 对象循环() {
    // 声明一个Peson类
    function Person() {
        this.name = "张三";
        this.age = 14;
        this.func1 = function () {}
    }
    // 实例化这个类
    var zhangsan = new Person();
    
    // 使用Object.values遍历这个对象
    for (let value of Object.values(zhangsan)) {
        log(value)
    }
}
对象循环()

4️⃣ for...of迭代器使用

ES6 借鉴 C++、Java、C# 和 Python 语言,引入了for…of循环,作为遍历所有数据结构的统一的方法。
一个数据结构只要部署了Symbol.iterator属性,就被视为具有iterator接口,就可以用for…of循环遍历它的成员。也就是说,for...of循环内部调用的是数据结构的Symbol.iterator方法

for…of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、Generator 对象,以及字符串。

错误示例:数字

正如上面所述,数字不是可迭代的对象,我们看下遍历不是可迭代的数字会发生什么。
在这里插入图片描述

所以,使用for...of时要谨慎,需要确保被遍历的是一个可以迭代的对象。相对的,for...in就安全多了,没有元素,啥也不做,直接返回。
在这里插入图片描述

字符串

字符串,直接遍历所有的字符,分别打印。
示例:

    // 字符串
    var str = "hello";
    for (let s of str) {
        log(s); // h e l l o
    }

Set

  • 遍历的顺序是按照各个成员被添加进数据结构的顺序。
  • 返回的是一个值
    示例:
    var engines = new Set(["Gecko", "Webkit", "Trident", "Webkit"]);
    for (var e of engines) {
        log(e);
    }
    // Gecko  Trident    Webkit

Map

  • 遍历的顺序是按照各个成员被添加进数据结构的顺序。
  • 返回的是一个数组,该数组的两个成员分别为当前 Map 成员的键名和键值。
    示例:
    var es6 = new Map();
    es6.set("standard", "ECMA-262");
    es6.set("edition", 6);
    es6.set("committee", "TC39");
    for (var [name, value] of es6) {
        log(name + ": " + value);
    }
    // edition: 6
    // committee: TC39
    // standard: ECMA-262

类似数组的对象

for...of应用场景很多,下面对TypedArray、DOM NodeList 对象、arguments对象分别举例说明。
示例:

    // TypedArray
    // 迭代 TypedArray - 一个类型化数组,描述了一个底层的二进制数据缓冲区!
    let iterable = new Uint8Array([0x00, 0xff]);
    for (let value of iterable) {
        log(value);//0 255
    }

    // DOM NodeList对象
    // let paras = document.querySelectorAll("p");
    // for (let p of paras) {
    //     p.classList.add("test");
    // }

    // arguments对象
    function printArgs() {
        for (let x of arguments) {
            log(x);
        }
    }
    printArgs('a', 'b'); // 'a' 'b'

🛬 文章小结

本篇是JavaScript基础的一个汇总,需要多写多练,多复习,才能强化记忆。
下面从不同方面对本节内容进行总结,如有纰漏,欢迎指正。

ps: for…of遍历,需要ES6支持。

性能差异

在测试环境、测试数据条件一致的情况下,各种语法函数的性能排序为:
for > for of > forEach > map > for in

  • for: 因为没有额外的函数调用和上下文,所以性能是最快的。
  • for ... of: 具有 iterator 接口的数据结构,可以使用它来迭代成员,直接读取键值。
  • forEach: 是 for 的语法糖,还有许多的参数和上下文,因此会慢一些。
  • map: 因为它返回的是一个等长的全新数组,数组创建和赋值产生的性能开销较大。
  • for...in: 性能最差,因为需要列举对象的所有属性,有转化过程,开销比较大。

功能差异

  • for await … of 能够支持异步操作,其他的不支持。
  • 对于纯对象的遍历, for … in 枚举更方便。
  • forEach、map等不支持跳出循环
  • 一个数组映射成另一个数组,使用 map、filter 等方法,支持链式调用

for await … of

for await ... of 能够支持异步操作,其他的不支持。
创建一个循环,该循环遍历异步可迭代对象以及同步可迭代对象,包括内置的 String、Array,类数组对象(arguments 或 nodeList),TypedArray, Map, Set 和用户定义的异步/同步迭代器。
它使用对象的每个不同属性的值调用要执行的语句来调用自定义迭代钩子。
类似于 await 运算符一样,该语句只能在一个async function 内部使用

function for_await_of循环() {
    async function* asyncGenerator() {
        var i = 0;
        while (i < 3) {
            yield i++;
        }
    }
    (async function () {
        for await (num of asyncGenerator()) {
            log(num);// 0 1 2
        }
    })();
}
// for_await_of循环()

📖 参考资料

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜猫逐梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值