Heim  >  Artikel  >  Web-Frontend  >  Ausführliche Erklärung, warum die Traversal-Methode in JavaScript dem Schleifencode vorgezogen wird

Ausführliche Erklärung, warum die Traversal-Methode in JavaScript dem Schleifencode vorgezogen wird

伊谢尔伦
伊谢尔伦Original
2017-07-26 17:04:471069Durchsuche

Priorisieren Sie die Verwendung von Traversal-Methoden gegenüber Schleifen

Bei der Verwendung von Schleifen kann es leicht zu einer Verletzung des DRY-Prinzips (Don't Repeat Yourself) kommen. Dies liegt daran, dass wir normalerweise die Methode „Kopieren und Einfügen“ wählen, um zu vermeiden, dass Absätze von Zirkelanweisungen handschriftlich geschrieben werden. Dies führt jedoch zu einer Menge doppeltem Code im Code, und Entwickler werden sinnlos „das Rad neu erfinden“. Noch wichtiger ist, dass beim Kopieren und Einfügen leicht die Details in der Schleife übersehen werden, z. B. der Startindexwert, die Beendigungsbedingung usw.

Zum Beispiel tritt dieses Problem bei der folgenden for-Schleife auf, vorausgesetzt, dass n die Länge des Sammlungsobjekts ist:


for (var i = 0; i <= n; i++) { ... }
// 终止条件错误,应该是i < n
for (var i = 1; i < n; i++) { ... }
// 起始变量错误,应该是i = 0
for (var i = n; i >= 0; i--) { ... }
// 起始变量错误,应该是i = n - 1
for (var i = n - 1; i > 0; i--) { ... }
// 终止条件错误,应该是i >= 0

Es kann in gesehen werden einige Details der Schleife Es ist leicht, Fehler zu machen. Mithilfe des von JavaScript bereitgestellten Abschlusses (siehe Punkt 11) können die Details der Schleife zur Wiederverwendung gekapselt werden. Tatsächlich bietet ES5 einige Methoden zur Lösung dieses Problems. Unter diesen ist Array.prototype.forEach das einfachste. Damit können wir die Schleife wie folgt schreiben:


// 使用for循环
for (var i = 0, n = players.length; i < n; i++) {
  players[i].score++;
}

// 使用forEach
players.forEach(function(p) {
  p.score++;
});

Zusätzlich zum Durchlaufen des Sammlungsobjekts besteht ein weiteres gängiges Muster darin, jedes Element in der ursprünglichen Sammlung zu durchqueren. Führen Sie bestimmte Operationen an Elementen aus und erhalten Sie dann einen neuen Satz. Wir können auch die forEach-Methode verwenden, um Folgendes zu implementieren:


// 使用for循环
var trimmed = [];
for (var i = 0, n = input.length; i < n; i++) {
  trimmed.push(input[i].trim());
}

// 使用forEach
var trimmed = [];
input.forEach(function(s) {
  trimmed.push(s.trim());
});

Aufgrund dieser Methode von Konvertieren einer Menge Das Muster der Zuordnung einer anderen Sammlung ist sehr verbreitet, und ES5 bietet auch die Methode Array.prototype.map, um den Code einfacher und eleganter zu machen:


var trimmed = input.map(function(s) {
  return s.trim();
});

Darüber hinaus besteht ein gängiges Muster darin, die Sammlung nach bestimmten Bedingungen zu filtern und dann eine Teilmenge der ursprünglichen Sammlung zu erhalten. Array.prototype.filter wird in ES5 bereitgestellt, um diesen Modus zu implementieren. Diese Methode akzeptiert ein Prädikat als Parameter, eine Funktion, die „true“ oder „false“ zurückgibt: Die Rückgabe von „true“ bedeutet, dass das Element in der neuen Sammlung beibehalten wird; die Rückgabe von „false“ bedeutet, dass das Element nicht in der neuen Sammlung angezeigt wird. Beispielsweise verwenden wir den folgenden Code, um Produktpreise zu filtern und nur Produkte mit Preisen im Bereich [min, max] zu behalten:


listings.filter(function(listing) {
  return listing.price >= min && listing.price <= max;
});

Natürlich das oben Genannte Methode Ist in Umgebungen verfügbar, die ES5 unterstützen. In anderen Umgebungen haben wir zwei Möglichkeiten: 1. Verwenden Sie Bibliotheken von Drittanbietern wie Underscore oder Lodash, die zahlreiche gängige Methoden zum Betreiben von Objekten und Sammlungen bereitstellen. 2. Definieren Sie es nach Bedarf.

Definieren Sie beispielsweise die folgende Methode, um die vorherigen Elemente im Satz basierend auf einer bestimmten Bedingung abzurufen:


function takeWhile(a, pred) {
  var result = [];
  for (var i = 0, n = a.length; i < n; i++) {
    if (!pred(a[i], i)) {
      break;
    }
    result[i] = a[i];
  }
  return result;
}

var prefix = takeWhile([1, 2, 4, 8, 16, 32], function(n) {
  return n < 10;
}); // [1, 2, 4, 8]

Um eine bessere Wiederverwendung zu ermöglichen Diese Methode können wir für das Array.prototype-Objekt definieren. Informationen zu spezifischen Effekten finden Sie in Punkt 42.


Array.prototype.takeWhile = function(pred) {
  var result = [];
  for (var i = 0, n = this.length; i < n; i++) {
    if (!pred(this[i], i)) {
      break;
    }
    result[i] = this[i];
  }
  return result; 
};

var prefix = [1, 2, 4, 8, 16, 32].takeWhile(function(n) {
  return n < 10;
}); // [1, 2, 4, 8]

Es gibt nur eine Situation, in der die Verwendung einer Schleife besser ist als die Verwendung einer Traversal-Funktion: wenn Sie Pause und Fortfahren verwenden müssen. Beispielsweise treten Probleme auf, wenn forEach zur Implementierung der oben genannten takeWhile-Methode verwendet wird. Wie sollte sie implementiert werden, wenn das Prädikat nicht erfüllt ist?


function takeWhile(a, pred) {
  var result = [];
  a.forEach(function(x, i) {
    if (!pred(x)) {
      // ?
    }
    result[i] = x;
  });
  return result;
}

Wir können eine interne Ausnahme verwenden, um das Urteil zu fällen, aber es ist auch etwas umständlich und ineffizient:


function takeWhile(a, pred) {
  var result = [];
  var earlyExit = {}; // unique value signaling loop break
  try {
    a.forEach(function(x, i) {
      if (!pred(x)) {
        throw earlyExit;
      }
      result[i] = x;
    });
  } catch (e) {
    if (e !== earlyExit) { // only catch earlyExit
      throw e;
    }
  }
  return result;
}

Aber nach der Verwendung von forEach ist der Code noch ausführlicher als vor der Verwendung. Das ist offensichtlich problematisch. Für dieses Problem bietet ES5 einige Methoden zur Behandlung von Schleifen, die vorzeitig beendet werden. Ihre Verwendung ist wie folgt:


[1, 10, 100].some(function(x) { return x > 5; }); // true
[1, 10, 100].some(function(x) { return x < 0; }); // false

[1, 2, 3, 4, 5].every(function(x) { return x > 0; }); // true
[1, 2, 3, 4, 5].every(function(x) { return x < 3; }); // false

Beide Methoden sind ein Kurzschluss Methode: Solange ein Element im Prädikat der Methode „some“ zurückgibt, wird „some“ zurückgegeben. Solange ein Element im Prädikat der Methode „Every“ zurückgegeben wird, gibt die Methode „Every“ auch „Falsch“ zurück.

Daher kann takeWhile wie folgt implementiert werden:


function takeWhile(a, pred) {
  var result = [];
  a.every(function(x, i) {
    if (!pred(x)) {
      return false; // break
    }
    result[i] = x;
    return true; // continue
  });
  return result;
}

Tatsächlich ist dies die Idee der funktionalen Programmierung. In der funktionalen Programmierung sieht man selten explizite For- oder While-Schleifen. Die Details der Schleifen sind schön gekapselt.

Das obige ist der detaillierte Inhalt vonAusführliche Erklärung, warum die Traversal-Methode in JavaScript dem Schleifencode vorgezogen wird. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn