JavaScript中的所有循环类型

在英语中, Loop 这个词指的是由弯曲的曲线所产生的形状。类似的概念, Loop 这个词已经被用于编程中。如果你看到下图,你就会清楚的知道指令的流动是如何在一个循环的动作中不断重复的。

在编程中,循环的概念并不是什么新概念,它们常常在编码时使用。虽然不是的语言其语法不同,但基本概念是相同的, 根据需要重复相同的代码块 。JavaScript增加了循环类型(包括各种类型的循环),并使其与它们的工作更加舒适和高效。在本文中,我们将学习JavaScript中所有可用的循环。

循环的定义

在计算机编程中, Loop 是一个重复特定代码块的过程。

JavaScript的循环类型

在JavaScript中有七种循环类型。我们已经把它们列出来,这样可以帮助你更清楚地了解他们的工作流程和使用情况。本文还将帮助你区分这七种循环类型,比如在哪里、何时或如何使用它们。让我们开始吧。

while 循环

while 循环是JavaScript中可用的最基本的循环类型之一。你一定听说过,JavaScript不是唯一的编程语言。

while 语句生成一个循环,在条件为 true 的情况下,在一个特定的语句块中执行该循环。每次执行代码块之前,条件都会被检查。

语法

while (条件) {
    // 代码块
}

示例

var i = 8;
while (i < 10) {
    console.log('我小于10')
    i++
}

在上面的例子中,条件 (i < 10) 先会被检查,如果条件为 truewhile 中的代码块就会被执行,而且再下一次迭代之前, i 的值将增加 1 ,主要是因为我们已经添加了一个 i++ 语句。

do-while 循环

do-whilewhile 略有不同,因为它包含一个额外的特性,最少执行一次。

语法

do {
    // 代码块
}
while (条件)

示例

var i = 8;
do {
    console.log('我的值是' + i)
    i++
}
while (i > 7 && i < 10)

你可以看到,我们的条件是 (i > 7 && i < 10) ,但 i=7 的时候值已经打印出来了。因为这个循环技术首先执行代码块,而不是考虑条件,执行完代码块之后,在第二轮的时候才执行条件。对于第二次循环遍历代码块时,只有条件为 true 才将执行。

for 循环

while 循环和 for 循环的工作方式完全相同,即使执行时间也没有太大差别。那么,另一个提供相同功能的循环系统需要什么呢?

for 循环中,循环的变量声明和初始化,条件查询和循环变量的递增或递减都可以在相同的行中完成。它增加了可读性,降低了出错的几率。

语法

for ([变量初始化];[条件];[变量递增或递减]) {
    // 代码块
}

示例

for (var i = 0; i  < 10; i++) {
    console.log('我的值是: ' + i)
}

正如上面的示例所示,变量初始化 i = 0 ,条件 i < 10 和变量的递增 i++ 都在同一行中声明。它更容易理解,可读性更好,是不是?

for 循环的使用和前面所说的 while 循环完全相同。但是为了让代码更容易阅读和理解,大多数的时候我们使用 for 循环而不是 while 循环。

forEach()

它是数组的原型方法(甚至是 mapset )。 forEach() 方法根据索引顺序 index ,每次使用数组中的每个元素调用一个给定的函数(或回调函数)。注意, forEach() 没有对没有值的数组元素运行给定的函数。

语法

array.forEach(function(currentValue, index, array){
    // 函数主体
})

forEach() 方法以函数作为参数。该函数由三个参数组成:

  • currentValue :保存正在处理的当前值
  • index :保存该特定数组中的值的索引
  • array :保存了整个数组

你可以使用 forEach() 遍历一个集合 set ,也可以使用它迭代一个映射 map

示例

var array = [10, 20, "hi", , {}, function () {console.log('我是一个函数')}]

array.forEach(function(item, index){
    console.log('array [' + index + '] 是: '+ item)
})

forEach() 方法遍历的是 array 数组。如果你没有使用索引 index ,你只能使用 array.forEach(function(item){}) 。可以相应地使用参数,但不是每次都要使用这三个参数。

使用 forEach() 让我们遍历数组变得非常的简单。不必担心循环变量、条件和其他任何东西,它会处理所有迭代的问题。

forEach()for 的区别

你可以使用一个从 0 开始到 array.length (该数组长度)简单的遍历一个数组。那么为什么还要提出不同的选择呢?

一个经验法则是,如果你可以选择使用原型方法,你就应该使用原型方法。因为,原型方法更清楚地知道对象,并对最佳方法进行了优化。下面这个示例能更好的来说明他们的区别之处:

var arr = [];
arr[0]=0;
arr[10]=10;

for(var i=0; i<arr.length; i++){
    console.log("I am for:" + i);
}

arr.forEach(function(){
    console.log("I am forEach");
});

如果你运行上面的代码,你会发现 for 打印了 11 次,而 forEach() 只打印了两次:

原因是, for 循环是一个简单的 for 循环,对它的用途一无所知。它从 0arr.length 。然而,当你使用 forEach() 的时候,它知道 arr 只有两个元素,虽然长度是 10 。累此,它实际上只迭代了两次。

根据这个,如果你想在循环中跳过繁重的工作,迭代一个 iterable ,你应该使用 forEach() 。然而,仅仅迭代(相同数量的迭代)的迭代时间相对于 for 循环来说是次要的。因为迭代性能更好。

map()

map 是数组的另一个原型方法。 map() 方法将创建一个新的数组,该数组的返回值由一个给定的数组的函数执行生成。

语法

var newArray= oldArray.map(function (currentValue, index, array){
    //Return element for the newArray
});

map() 方法以函数作为参数,该函数有三个参数:

  • currentValue : 在数组中处理的当前元素
  • index :数组中正在处理的当前元素的索引值
  • array :数组映射的调用

示例

var num = [1, 5, 10, 15];
var doubles = num.map(function(x) {
    return x * 2;
});

在上面的示例中,名为 doubles 的新数组将输出 doubles=[2, 10, 20, 30]num 数组仍旧是 num=[1, 5, 10, 15]

for…in

这个方法主要是对象的迭代。 for...in 在语句中迭代对象的可枚举属性。对于每个不同的属性,可以执行语句。

因为我们知道数组也是一种特殊的对象,所以不要认为数组不能用这个来进行迭代。

语法

for (variableName in object) {
    Block of code
}

示例

var obj = {a: 1, b: 2, c: 3};    
for (var prop in obj) {
    console.log('obj.'+prop+'='+obj[prop]);
};

为什么在数组中使用 for...in 迭代不可取?

for...in 不应该在数组迭代中使用,特别是 index 顺序非常重要。

实际上,数组索引和一般对象属性之间没有区别,数组索引只是可枚举属性。

for...in 不会每次都以任何特定的顺序返回 index 值。 for...in 在迭代中,这个循环将返回所有可枚举属性,包括那些具有非整数名称的属性和继承的属性。

因此,建议在遍历数组时使用 forforEach() 。因为迭代的顺序是依赖于现实的迭代,并且遍历一个数组,使用 for...in 可能不会以一致的顺序访问元素。

var arr = [];
arr[2] = 2;
arr[3] = 3;
arr[0] = 0;
arr[1] = 1;

在这种情况下,使用 forEach() 将输出一个 0, 1, 2, 3 。但使用 for...in 并不能保证会输出什么。

对于 for...in 还有一件事你应该记住,它遍历对象的所有属性,包括继承的(来自父类)。如果只想在对象自己的属性上进行迭代,那么应该执行下面这样的操作:

for(var prop in obj){
    if(obj.hasOwnProperty(prop)){
        Code block here
    }
}

for…of

这是ES6中新引入的一种循环类型。使用 for...of 语句,你可以遍历任何可迭代的对象,比如 ArrayStringMapWeakMapSet 、参数对象、 TypeArray ,甚至一般对象。

语法

for (variable of iterable) {
    Block of code
}

示例

var str= 'paul';
for (var value of str) {
    console.log(value);
}

map的迭代

let itobj = new Map([['x', 0], ['y', 1], ['z', 2]]);

for (let kv of itobj) {
    console.log(kv);
}
// => ['x', 0]
// => ['y', 1]
// => ['z', 2]

for (let [key, value] of itobj) {
    console.log(value);
}

// => 0
// => 1
// => 2

for...in 循环主要遍历对象,其实际的插入顺序中是可枚举的属性; for...of 迭代任何可迭代对象的给定值(而不是属性名)。

Object.prototype.objProto = function() {}; 
Array.prototype.arrProto = function() {};

let iterable = [8, 55, 9];
iterable.title = 'VoidCanvas';

for (let x in iterable) {
    console.log(x); // logs 0, 1, 2, title, arrProto, objProto
}

for (let i of iterable) {
    console.log(i); //  8, 55, 9
}

正如你所见, for...of 都是关于对象自己 value 的迭代,而 for...in 将会考虑原型和继承的属性。如果你想在对象上迭代(而不是迭代)。 for...of 将会考虑它自己的所有属性,但迭代的情交下,它只会考虑适合这种迭代的元素。这就是为什么在上面的例子中, for...of 没有迭代属性。

本文根据 @Sandip 的《 The Output Element 》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处: http://voidcanvas.com/all-type-of-loops-in-javascript-a-brief-explanation

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《 图解CSS3:核心技术与案例实战 》。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章