𝗥𝗲𝘀𝗲𝗮𝗿𝗰𝗵 𝗔𝗻𝗱 𝗥𝗲𝘀𝘂𝗹𝘁𝘀
Für die Fakten werden ein Leistungstest bei jsperf und die Überprüfung einiger Dinge in der Konsole durchgeführt. Für die Recherche wird die Website irt.org verwendet. Unten finden Sie eine Sammlung all dieser Quellen sowie eine Beispielfunktion unten.
╔═══════════════╦══════╦═════════════════╦════════ ═══════╦═════════╦══════════╗
║ Methode ║Concat║slice & push.apply ║ push.apply x2 ║ ForLoop ║Spread ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ mOps / Sec ║179 ║104 ║ 76 ║ 81 ║28 ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ Sparse Arrays ║ JA! »Nur die in Scheiben geschnittenen ║ nein ║ Vielleicht 2 ║ nein ║
║ spärlich gehalten ║ ║array (1. Argument) ║ ║ ║ ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ Unterstützung ║MSIE 4║MSIE 5.5 ║ MSIE 5.5 ║ MSIE 4 ║Edge 12 ║
Source ( Quelle ) ║NNav 4║NNav 4.06 ║NNav 4.06 ║NNav 3 ║ MSIE NNav ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║Array-ähnliche Handlungen║nein theNur das Geschobene ║ JA! ║ JA! FWenn ║
║wie ein Array ║ ║array (2. Argument) ║ ║iterator 1 ║
╚═══════════════╩══════╩═════════════════╩════════ ═══════╩═════════╩══════════╝
1 Wenn das Array-ähnliche Objekt keine Symbol.iterator- Eigenschaft hat, versuchen Sie es
um es zu verbreiten, wird eine Ausnahme ausgelöst.
2 Hängt vom Code ab. Der folgende Beispielcode "YES" bewahrt die Spärlichkeit.
function mergeCopyTogether(inputOne, inputTwo){
var oneLen = inputOne.length, twoLen = inputTwo.length;
var newArr = [], newLen = newArr.length = oneLen + twoLen;
for (var i=0, tmp=inputOne[0]; i !== oneLen; ++i) {
tmp = inputOne[i];
if (tmp !== undefined || inputOne.hasOwnProperty(i)) newArr[i] = tmp;
}
for (var two=0; i !== newLen; ++i, ++two) {
tmp = inputTwo[two];
if (tmp !== undefined || inputTwo.hasOwnProperty(two)) newArr[i] = tmp;
}
return newArr;
}
Wie oben gezeigt, würde ich argumentieren, dass Concat fast immer der richtige Weg ist, um sowohl Leistung als auch die Fähigkeit zu erhalten, die Spärlichkeit von Ersatz-Arrays beizubehalten. Dann document.body.children
würde ich für Array-Likes (wie DOMNodeLists wie ) die Verwendung der for-Schleife empfehlen, da sie sowohl die zweitperformanteste als auch die einzige andere Methode ist, die spärliche Arrays beibehält. Im Folgenden werden wir schnell darauf eingehen, was unter spärlichen Arrays und Array-Likes zu verstehen ist, um Verwirrung zu beseitigen.
𝗧𝗵𝗲 𝗙𝘂𝘁𝘂𝗿𝗲
Zunächst denken einige Leute vielleicht, dass dies ein Zufall ist und dass Browser-Anbieter irgendwann dazu kommen werden, Array.prototype.push so zu optimieren, dass es schnell genug ist, um Array.prototype.concat zu schlagen. FALSCH! Array.prototype.concat ist immer schneller (zumindest im Prinzip), da es sich um ein einfaches Kopieren und Einfügen über die Daten handelt. Unten finden Sie ein vereinfachtes, überzeugend-visuelles Diagramm, wie eine 32-Bit-Array-Implementierung aussehen könnte (bitte beachten Sie, dass echte Implementierungen viel komplizierter sind).
Byte ║ Daten hier
═════╬═══════════
0x00 ║ int nonNumericPropertiesLength = 0x00000000
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ int Länge = 0x00000001
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ int valueIndex = 0x00000000
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ int valueType = JS_PRIMITIVE_NUMBER
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ uintptr_t valuePointer = 0x38d9eb60 (oder wo immer es sich im Speicher befindet)
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
Wie oben gezeigt, ist alles, was Sie tun müssen, um so etwas zu kopieren, fast so einfach wie das Byte-für-Byte-Kopieren. Mit Array.prototype.push.apply ist es viel mehr als ein einfaches Kopieren und Einfügen über die Daten. Die ".apply" muss jeden Index im Array überprüfen und in eine Reihe von Argumenten konvertieren, bevor sie an Array.prototype.push übergeben wird. Dann muss Array.prototype.push jedes Mal zusätzlich mehr Speicher zuweisen und (für einige Browser-Implementierungen) möglicherweise sogar einige Positionssuchdaten für die Spärlichkeit neu berechnen.
Eine alternative Art, darüber nachzudenken, ist dies. Das Quellarray 1 ist ein großer Stapel zusammengehefteter Papiere. Das Quellarray zwei ist ebenfalls ein großer Papierstapel. Wäre es schneller für dich?
- Gehen Sie in den Laden und kaufen Sie genügend Papier, um eine Kopie jedes Quellarrays zu erhalten. Führen Sie dann jeden Papierstapel des Quellarrays durch ein Kopiergerät und heften Sie die resultierenden zwei Kopien zusammen.
- Gehen Sie in den Laden und kaufen Sie genug Papier für eine einzelne Kopie des ersten Quellarrays. Kopieren Sie dann das Quellarray von Hand auf das neue Papier, und achten Sie darauf, dass alle leeren Stellen mit geringer Dichte ausgefüllt werden. Gehen Sie dann zurück in den Laden und kaufen Sie genügend Papier für das zweite Quellarray. Gehen Sie dann das zweite Quellarray durch und kopieren Sie es, ohne dass Lücken in der Kopie entstehen. Heften Sie dann alle kopierten Papiere zusammen.
In der obigen Analogie steht Option 1 für Array.prototype.concat, während Option 2 für Array.prototype.push.apply steht. Lassen Sie uns dies mit einem ähnlichen JSperf testen, der sich nur darin unterscheidet, dass dieser die Methoden über spärliche Arrays und nicht über feste Arrays testet. Man kann es hier finden .
Daher ruhe ich meinen Fall aus, dass die Zukunft der Leistung für diesen speziellen Anwendungsfall nicht in Array.prototype.push liegt, sondern in Array.prototype.concat.
𝗖𝗹𝗮𝗿𝗶𝗳𝗶𝗰𝗮𝘁𝗶𝗼𝗻𝘀
𝗦𝗽𝗮𝗿𝗲 𝗔𝗿𝗿𝗮𝘆𝘀
Wenn bestimmte Mitglieder des Arrays einfach fehlen. Zum Beispiel:
// This is just as an example. In actual code,
// do not mix different types like this.
var mySparseArray = [];
mySparseArray[0] = "foo";
mySparseArray[10] = undefined;
mySparseArray[11] = {};
mySparseArray[12] = 10;
mySparseArray[17] = "bar";
console.log("Length: ", mySparseArray.length);
console.log("0 in it: ", 0 in mySparseArray);
console.log("arr[0]: ", mySparseArray[0]);
console.log("10 in it: ", 10 in mySparseArray);
console.log("arr[10] ", mySparseArray[10]);
console.log("20 in it: ", 20 in mySparseArray);
console.log("arr[20]: ", mySparseArray[20]);
Alternativ können Sie mit Javascript Ersatzarrays einfach initialisieren.
var mySparseArray = ["foo",,,,,,,,,,undefined,{},10,,,,,"bar"];
𝗔𝗿𝗿𝗮𝘆-𝗟𝗶𝗸𝗲𝘀
Ein Array-ähnliches Objekt ist ein Objekt, das mindestens eine length
Eigenschaft hat, jedoch nicht mit new Array
oder initialisiert wurde []
. Beispielsweise werden die folgenden Objekte als Array-ähnlich klassifiziert.
{0: "foo", 1: "bar", Länge: 2}
document.body.children
neues Uint8Array (3)
- Dies ist Array-ähnlich, da das Konstruieren in ein Array den Konstruktor ändert, obwohl es sich um ein (n) (typisiertes) Array handelt.
(function () {Argumente zurückgeben}) ()
Beobachten Sie, was mit einer Methode passiert, die Array-Likes in Arrays wie Slice zwingt.
var slice = Array.prototype.slice;
// For arrays:
console.log(slice.call(["not an array-like, rather a real array"]));
// For array-likes:
console.log(slice.call({0: "foo", 1: "bar", length:2}));
console.log(slice.call(document.body.children));
console.log(slice.call(new Uint8Array(3)));
console.log(slice.call( function(){return arguments}() ));
- ANMERKUNG: Aufgrund der Leistung wird empfohlen, Slice-on-Funktionsargumente aufzurufen.
Beobachten Sie, was ein Verfahren geschieht verwenden , die sich nicht Array-likes in Arrays wie concat zwingen.
var empty = [];
// For arrays:
console.log(empty.concat(["not an array-like, rather a real array"]));
// For array-likes:
console.log(empty.concat({0: "foo", 1: "bar", length:2}));
console.log(empty.concat(document.body.children));
console.log(empty.concat(new Uint8Array(3)));
console.log(empty.concat( function(){return arguments}() ));