In ECMAScript5 (kurz ES5) gibt es drei Arten von for-Schleifen, nämlich:
Einfache for-Schleife
for-in
forEach
In ECMAScript6 (kurz ES6), das im Juni 2015 veröffentlicht wurde, wurde eine neue Schleife hinzugefügt. ist:
for-of
Werfen wir einen Blick auf diese 4 Arten von for-Schleifen.
Werfen wir einen Blick auf die gebräuchlichste Schreibweise:
const arr = [1, 2, 3]; for(let i = 0; i < arr.length; i++) { console.log(arr[i]); }
Wenn sich die Länge des Arrays während der Schleife nicht ändert, wir Die Länge des Arrays sollte in einer Variablen gespeichert werden, um eine bessere Effizienz zu erzielen. Das Folgende ist eine verbesserte Schreibweise:
const arr = [1, 2, 3]; for(let i = 0, len = arr.length; i < len; i++) { console.log(arr[i]); }
Normalerweise können wir verwenden Um den Inhalt des Arrays zu durchlaufen, lautet der Code wie folgt:
const arr = [1, 2, 3]; let index; for(index in arr) { console.log("arr[" + index + "] = " + arr[index]); }
Im Allgemeinen lauten die laufenden Ergebnisse wie folgt:
arr[0] = 1 arr[1] = 2 arr[2] = 3
Aber das führt oft zu Problemen .
Die Wahrheit über die For-In-
For-In-Schleife durchläuft die Eigenschaften des Objekts, nicht den Index des Arrays. Daher sind die von for-in durchlaufenen Objekte nicht auf Arrays beschränkt, sondern können auch Objekte durchlaufen. Ein Beispiel lautet wie folgt:
const person = { fname: "san", lname: "zhang", age: 99 }; let info; for(info in person) { console.log("person[" + info + "] = " + person[info]); }
Das Ergebnis ist wie folgt:
person[fname] = san person[lname] = zhang person[age] = 99
Es ist zu beachten, dass die Reihenfolge, in der for-in die Attribute durchläuft, nicht bestimmt ist Das heißt, die Reihenfolge der Ausgabeergebnisse ist dieselbe wie die Reihenfolge der Attribute im Objekt. Die Reihenfolge von , die alphabetische Reihenfolge der Eigenschaften oder eine andere Reihenfolge ist irrelevant.
Die Wahrheit über Array
Array ist ein Objekt in Javascript und der Index von Array ist der Eigenschaftsname. Tatsächlich ist „Array“ in Javascript etwas irreführend. Erstens ist Array in Javascript im Speicher nicht kontinuierlich. Zweitens bezieht sich der Index von Array nicht auf den Offset. Tatsächlich ist der Index des Arrays nicht vom Typ „Zahl“, sondern vom Typ „String“. Der Grund, warum wir arr[0] korrekt verwenden können, liegt darin, dass die Sprache automatisch 0 vom Typ „Zahl“ in „0“ vom Typ „String“ konvertieren kann. Deshalb gibt es in Javascript nie Array-Indizes, sondern nur Eigenschaften wie „0“, „1“ usw. Interessanterweise verfügt jedes Array-Objekt über eine Längeneigenschaft, wodurch es sich eher wie Arrays in anderen Sprachen verhält. Aber warum wird das Längenattribut beim Durchlaufen des Array-Objekts nicht ausgegeben? Das liegt daran, dass for-in nur über „aufzählbare Eigenschaften“ iterieren kann, die Länge eine nicht aufzählbare Eigenschaft ist und Array-Objekte tatsächlich viele andere nicht aufzählbare Eigenschaften haben.
Lassen Sie uns nun zurückgehen und uns das Beispiel für die Verwendung von for-in zum Schleifen eines Arrays ansehen. Ändern wir das vorherige Beispiel für das Durchlaufen des Arrays:
const arr = [1, 2, 3]; arr.name = "Hello world"; let index; for(index in arr) { console.log("arr[" + index + "] = " + arr[index]); }
Das Ergebnis der Operation ist:
arr[0] = 1 arr[1] = 2 arr[2] = 3 arr[name] = Hello world
Wir sehen, dass das For-In eine Schleife durch unsere neue „Name“-Eigenschaft durchläuft, weil das For-In alle Eigenschaften des Objekts durchläuft, nicht nur den „Index“. Gleichzeitig ist zu beachten, dass die hier ausgegebenen Indexwerte, also „0“, „1“ und „2“, nicht vom Typ „Zahl“, sondern vom Typ „String“ sind, da sie als Attribute ausgegeben werden , keine Indizes. Bedeutet das, dass wir einfach den Inhalt des Arrays ausgeben können, ohne unserem Array-Objekt neue Eigenschaften hinzuzufügen? Die Antwort ist nein. Denn for-in durchläuft nicht nur die Eigenschaften des Arrays selbst, sondern auch alle aufzählbaren Eigenschaften in der Array-Prototypkette. Schauen wir uns unten ein Beispiel an:
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]); }
Das laufende Ergebnis ist:
arr[0] = 1 arr[1] = 2 arr[2] = 3 arr[name] = Hello world arr[fatherName] = Father
Wenn wir dies schreiben, können wir feststellen, dass for-in nicht zum Durchlaufen von Elementen in Array It geeignet ist eignet sich besser zum Durchlaufen der Eigenschaften im Objekt, was auch die ursprüngliche Absicht seiner Erstellung ist. Es gibt eine Ausnahme, nämlich spärliche Arrays. Betrachten Sie das folgende Beispiel:
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 durchläuft nur vorhandene Entitäten. Im obigen Beispiel durchläuft for-in dreimal (die Traversierungsattribute sind „0“, „100“, „For 10000“) ″-Elemente, eine normale for-Schleife wird 10001 Mal durchlaufen). Solange es richtig gemacht wird, kann for-in auch eine große Rolle beim Durchlaufen von Elementen in einem Array spielen.
Um Doppelarbeit zu vermeiden, können wir den obigen Code umschließen:
function arrayHasOwnIndex(array, prop) { return array.hasOwnProperty(prop) && /^0$|^[1-9]\d*$/.test(prop) && prop <= 4294967294; // 2^32 - 2 }
Verwendungsbeispiele sind wie folgt:
for (let key in arr) { if (arrayHasOwnIndex(arr, key)) { console.log(arr[key]); } }
für- in der Leistung
Wie oben erwähnt, sucht jeder Iterationsvorgang gleichzeitig nach Instanz- oder Prototypeigenschaften. Jede Iteration der for-in-Schleife erzeugt mehr Overhead, sodass sie langsamer ist als andere Schleifen Typen, im Allgemeinen schneller als andere Typen, Zyklus 1/7. Daher sollten Sie die Verwendung von For-In-Schleifen vermeiden, es sei denn, Sie müssen eindeutig über ein Objekt mit einer unbekannten Anzahl von Eigenschaften iterieren. Wenn Sie eine begrenzte Anzahl bekannter Attributlisten durchlaufen müssen, ist es schneller, andere Schleifen zu verwenden, wie zum Beispiel das folgende Beispiel:
const obj = { "prop1": "value1", "prop2": "value2" }; const props = ["prop1", "prop2"]; for(let i = 0; i < props.length; i++) { console.log(obj[props[i]]); }
Im obigen Code werden die Attribute des Objekts gespeichert ein Array, relativ zur For-In-Suche nach jedem Attribut. Dieser Code konzentriert sich nur auf das angegebene Attribut und spart so den Overhead und die Zeit der Schleife.
In ES5 wird eine neue Schleife eingeführt, die forEach-Schleife.
const arr = [1, 2, 3]; arr.forEach((data) => { console.log(data); });
Betriebsergebnisse:
1 2 3
Die forEach-Methode führt eine Rückruffunktion für jedes Element im Array aus, das einen gültigen Wert enthält, also diejenigen, die gelöscht wurden (mit der Methode delete). usw.) oder von Nicht zugewiesenen Elementen werden übersprungen (mit Ausnahme derjenigen mit undefinierten oder Nullwerten). Die Rückruffunktion wird in drei Parametern nacheinander übergeben:
数组当前项的值;
数组当前项的索引;
数组对象本身;
需要注意的是,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。如果大家把测试代码放在控制台的话,可能会得到不一样的结果,主要原因是控制台的执行环境与真实的代码执行环境有所区别。
先来看个例子:
const arr = ['a', 'b', 'c']; 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 = ['a', 'b', 'c']; const iter = arr[Symbol.iterator](); iter.next() // { value: 'a', done: false } iter.next() // { value: 'b', done: false } iter.next() // { value: 'c', done: false } iter.next() // { value: undefined, done: true }
不过,这个内容超出了本文的范围,而且 Iterator 要讲的也有很多,以后有时间专门写一篇文章介绍,欢迎关注。
以上就是深入了解 JavaScript 中的 for 循环 的详细介绍 的内容,更多相关内容请关注PHP中文网(www.php.cn)!