Maison  >  Article  >  interface Web  >  Une introduction détaillée à la boucle for en JavaScript

Une introduction détaillée à la boucle for en JavaScript

黄舟
黄舟original
2017-03-03 14:42:401069parcourir

Dans ECMAScript5 (ES5 en abrégé), il existe trois types de boucles for, à savoir :

  • Boucle for simple

  • for-in

  • forEach

Dans ECMAScript6 (ES6 en abrégé) sorti en juin 2015, une nouvelle boucle a été ajoutée, est :

  • for-of

Jetons un coup d'œil à ces 4 types de boucles for.

Boucle for simple

Jetons un coup d'œil à la manière d'écrire la plus courante :

const arr = [1, 2, 3];
for(let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}

Lorsque la longueur du tableau ne change pas pendant la boucle, nous La longueur du tableau doit être stockée dans une variable, ce qui permettra d'obtenir une meilleure efficacité. Ce qui suit est une façon améliorée d'écrire :

const arr = [1, 2, 3];
for(let i = 0, len = arr.length; i < len; i++) {
    console.log(arr[i]);
}

for-in

Habituellement, nous pouvons utiliser. pour parcourir le contenu du tableau, le code est le suivant :

const arr = [1, 2, 3];
let index;
for(index in arr) {
    console.log("arr[" + index + "] = " + arr[index]);
}

Généralement, les résultats d'exécution sont les suivants :

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

Mais cela pose souvent des problèmes .

La vérité sur la boucle for-in

for-in traverse les propriétés de l'objet, pas l'index du tableau. Par conséquent, les objets traversés par for-in ne se limitent pas aux tableaux, mais peuvent également traverser des objets. Un exemple est le suivant :

const person = {
    fname: "san",
    lname: "zhang",
    age: 99
};
let info;
for(info in person) {
    console.log("person[" + info + "] = " + person[info]);
}

Le résultat est le suivant :

person[fname] = san
person[lname] = zhang
person[age] = 99

Il est à noter que l'ordre dans lequel for-in parcourt les attributs n'est pas déterminé, que Autrement dit, l'ordre des résultats de sortie est le même que l'ordre des attributs dans l'objet. L'ordre des propriétés, l'ordre alphabétique ou tout autre ordre n'est pas pertinent.

La vérité sur Array

Array est un objet en Javascript, et l'index de Array est le nom de la propriété. En fait, "tableau" en Javascript est quelque peu trompeur. Le tableau en Javascript n'est pas comme les tableaux dans la plupart des autres langages. Tout d'abord, Array en Javascript n'est pas continu en mémoire. Deuxièmement, l'index de Array ne fait pas référence au décalage. En fait, l’index de Array n’est pas de type Number, mais de type String. La raison pour laquelle nous pouvons utiliser correctement arr[0] est que le langage peut automatiquement convertir 0 de type Number en "0" de type String. Par conséquent, il n'y a jamais d'index Array en Javascript, mais uniquement des propriétés telles que "0", "1", etc. Il est intéressant de noter que chaque objet Array possède une propriété length, ce qui le fait se comporter davantage comme des tableaux dans d'autres langages. Mais pourquoi l'attribut length n'est-il pas affiché lors du parcours de l'objet Array ? En effet, for-in ne peut parcourir que des "propriétés énumérables", la longueur est une propriété non énumérable et, en fait, les objets Array ont de nombreuses autres propriétés non énumérables.

Maintenant, revenons en arrière et regardons l'exemple d'utilisation de for-in pour boucler un tableau. Modifions l'exemple précédent de parcours du tableau :

const arr = [1, 2, 3];
arr.name = "Hello world";
let index;
for(index in arr) {
    console.log("arr[" + index + "] = " + arr[index]);
}

Le résultat de l'opération. est :

arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[name] = Hello world

Nous voyons que le for-in parcourt notre nouvelle propriété "name", car le for-in parcourt toutes les propriétés de l'objet, pas seulement "l'index". Dans le même temps, il convient de noter que les valeurs d'index sorties ici, c'est-à-dire "0", "1" et "2", ne sont pas de type Number, mais de type String, car elles sont sorties en tant qu'attributs. , pas les index. Cela signifie-t-il que nous pouvons simplement afficher le contenu du tableau sans ajouter de nouvelles propriétés à notre objet Array ? La réponse est non. Parce que for-in ne parcourt pas seulement les propriétés du tableau lui-même, il parcourt également toutes les propriétés énumérables de la chaîne de prototypes du tableau. Regardons un exemple ci-dessous :

Array.prototype.fatherName = "Father";
const arr = [1, 2, 3];
arr.name = "Hello world";
let index;
for(index in arr) {
    console.log("arr[" + index + "] = " + arr[index]);
}

Le résultat en cours d'exécution est :

arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[name] = Hello world
arr[fatherName] = Father

En écrivant ceci, nous pouvons constater que for-in n'est pas adapté pour parcourir des éléments dans Array It. est plus adapté pour parcourir les propriétés de l'objet, ce qui est également l'intention initiale de sa création. Il existe une exception : les tableaux clairsemés. Considérons l'exemple suivant :

let key;
const arr = [];
arr[0] = "a";
arr[100] = "b";
arr[10000] = "c";
for(key in arr) {
    if(arr.hasOwnProperty(key)  &&    
        /^0$|^[1-9]\d*$/.test(key) &&    
        key <= 4294967294               
        ) {
        console.log(arr[key]);
    }
}

for-in ne traversera que les entités existantes. Dans l'exemple ci-dessus, for-in traverse 3 fois (les attributs de traversée sont "0", "100", " For 10000). ″ éléments, une boucle for normale traversera 10001 fois). Ainsi, tant que cela est fait correctement, for-in peut également jouer un rôle important dans le parcours des éléments dans un tableau.

Afin d'éviter la duplication du travail, nous pouvons envelopper le code ci-dessus :

function arrayHasOwnIndex(array, prop) {
    return array.hasOwnProperty(prop) && 
        /^0$|^[1-9]\d*$/.test(prop) && 
        prop <= 4294967294; // 2^32 - 2
}

Les exemples d'utilisation sont les suivants :

for (let key in arr) {
    if (arrayHasOwnIndex(arr, key)) {
        console.log(arr[key]);
    }
}

pour- en performances

Comme mentionné ci-dessus, chaque opération d'itération recherchera des propriétés d'instance ou de prototype en même temps. Chaque itération de la boucle for-in générera plus de surcharge, elle est donc plus lente que les autres boucles. types, généralement plus rapides que les autres 1/7 du cycle de type. Par conséquent, vous devez éviter d’utiliser des boucles for-in, sauf si vous avez clairement besoin de parcourir un objet avec un nombre inconnu de propriétés. Si vous devez parcourir un nombre limité de listes d'attributs connus, il sera plus rapide d'utiliser d'autres boucles, comme l'exemple suivant :

const obj = {
    "prop1": "value1",
    "prop2": "value2"
};

const props = ["prop1", "prop2"];
for(let i = 0; i < props.length; i++) {
    console.log(obj[props[i]]);
}

Dans le code ci-dessus, les attributs de l'objet sont stockés dans un tableau, par rapport à for-in, recherche chaque attribut, et le code se concentre uniquement sur l'attribut donné, économisant ainsi la surcharge et le temps de la boucle.

forEach

Dans ES5, une nouvelle boucle est introduite, la boucle forEach.

const arr = [1, 2, 3];
arr.forEach((data) => {
    console.log(data);
});

Résultats de fonctionnement :

1
2
3

La méthode forEach exécute une fonction de rappel pour chaque élément du tableau qui contient une valeur valide, ceux qui ont été supprimés (en utilisant la méthode delete , etc.) ou des éléments non attribués sont ignorés (à l'exclusion de ceux avec des valeurs non définies ou nulles). La fonction de rappel sera transmise en trois paramètres dans l'ordre :

  • 数组当前项的值;

  • 数组当前项的索引;

  • 数组对象本身;

需要注意的是,forEach 遍历的范围在第一次调用 callback 前就会确定。调用forEach 后添加到数组中的项不会被 callback 访问到。如果已经存在的值被改变,则传递给 callback 的值是 forEach 遍历到他们那一刻的值。已删除的项不会被遍历到。

const arr = [];
arr[0] = "a";
arr[3] = "b";
arr[10] = "c";
arr.name = "Hello world";
arr.forEach((data, index, array) => {
    console.log(data, index, array);
});

运行结果:

a 0 ["a", 3: "b", 10: "c", name: "Hello world"]
b 3 ["a", 3: "b", 10: "c", name: "Hello world"]
c 10 ["a", 3: "b", 10: "c", name: "Hello world"]

这里的 index 是 Number 类型,并且也不会像 for-in 一样遍历原型链上的属性。

所以,使用 forEach 时,我们不需要专门地声明 index 和遍历的元素,因为这些都作为回调函数的参数。

另外,forEach 将会遍历数组中的所有元素,但是 ES5 定义了一些其他有用的方法,下面是一部分:

  • every: 循环在第一次 return false 后返回

  • some: 循环在第一次 return true 后返回

  • filter: 返回一个新的数组,该数组内的元素满足回调函数

  • map: 将原数组中的元素处理后再返回

  • reduce: 对数组中的元素依次处理,将上次处理结果作为下次处理的输入,最后得到最终结果。

forEach 性能

首先感谢@papa pa的提醒,才发现我之前的理解有错误。

大家可以看 jsPerf ,在不同浏览器下测试的结果都是 forEach 的速度不如 for。如果大家把测试代码放在控制台的话,可能会得到不一样的结果,主要原因是控制台的执行环境与真实的代码执行环境有所区别。

for-of

先来看个例子:

const arr = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;];
for(let data of arr) {
    console.log(data);
}

运行结果是:

a
b
c

为什么要引进 for-of?

要回答这个问题,我们先来看看ES6之前的 3 种 for 循环有什么缺陷:

  • forEach 不能 break 和 return;

  • for-in 缺点更加明显,它不仅遍历数组中的元素,还会遍历自定义的属性,甚至原型链上的属性都被访问到。而且,遍历数组元素的顺序可能是随机的。

所以,鉴于以上种种缺陷,我们需要改进原先的 for 循环。但 ES6 不会破坏你已经写好的 JS 代码。目前,成千上万的 Web 网站依赖 for-in 循环,其中一些网站甚至将其用于数组遍历。如果想通过修正 for-in 循环增加数组遍历支持会让这一切变得更加混乱,因此,标准委员会在 ES6 中增加了一种新的循环语法来解决目前的问题,即 for-of 。

那 for-of 到底可以干什么呢?

  • 跟 forEach 相比,可以正确响应 break, continue, return。

  • for-of 循环不仅支持数组,还支持大多数类数组对象,例如 DOM nodelist 对象。

  • for-of 循环也支持字符串遍历,它将字符串视为一系列 Unicode 字符来进行遍历。

  • for-of 也支持 Map 和 Set (两者均为 ES6 中新增的类型)对象遍历。

总结一下,for-of 循环有以下几个特征:

  • 这是最简洁、最直接的遍历数组元素的语法。

  • 这个方法避开了 for-in 循环的所有缺陷。

  • 与 forEach 不同的是,它可以正确响应 break、continue 和 return 语句。

  • 其不仅可以遍历数组,还可以遍历类数组对象和其他可迭代对象。

但需要注意的是,for-of循环不支持普通对象,但如果你想迭代一个对象的属性,你可以用
for-in 循环(这也是它的本职工作)。

最后要说的是,ES6 引进的另一个方式也能实现遍历数组的值,那就是 Iterator。上个例子:

const arr = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;];
const iter = arr[Symbol.iterator]();

iter.next() // { value: &#39;a&#39;, done: false }
iter.next() // { value: &#39;b&#39;, done: false }
iter.next() // { value: &#39;c&#39;, done: false }
iter.next() // { value: undefined, done: true }

不过,这个内容超出了本文的范围,而且 Iterator 要讲的也有很多,以后有时间专门写一篇文章介绍,欢迎关注。

 以上就是深入了解 JavaScript 中的 for 循环 的详细介绍 的内容,更多相关内容请关注PHP中文网(www.php.cn)!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn