Snelste manier om een array in JavaScript te dupliceren – slice versus ‘for’-lus

Om een array in JavaScript te dupliceren: Welke van de volgende is sneller te gebruiken?

slicemethode

var dup_array = original_array.slice();

Forlus

for(var i = 0, len = original_array.length; i < len; ++i)
   dup_array[i] = original_array[i];

Ik weet dat beide manieren slechts een ondiepe kopiedoen: als original_arrayverwijzingen naar objecten bevat, worden objecten niet gekloond, maar worden alleen de verwijzingen gekopieerd, en daarom hebben beide arrays verwijzingen naar dezelfde objecten.
Maar dit is niet het punt van deze vraag.

Ik vraag alleen naar snelheid.


Antwoord 1, autoriteit 100%

Er zijn minstens 6(!) manieren om een array te klonen:

  • lus
  • plakje
  • Array.from()
  • concat
  • spread-operator (SNELSTE)
  • kaart A.map(function(e){return e;});

Er is een enorme BENCHMARKS-threadgeweest, met de volgende informatie:

  • voor blinkbrowsers is slice()de snelste methode, concat()is iets langzamer en while loopis 2,4x langzamer.

  • voor andere browsers is while loopde snelste methode, aangezien die browsers geen interne optimalisaties hebben voor sliceen concat.

Dit blijft zo in juli 2016.

Hieronder staan eenvoudige scripts die u kunt kopiëren en plakken in de console van uw browser en meerdere keren kunt uitvoeren om de afbeelding te zien. Ze produceren milliseconden, lager is beter.

terwijl-lus

n = 1000*1000;
start = + new Date();
a = Array(n); 
b = Array(n); 
i = a.length;
while(i--) b[i] = a[i];
console.log(new Date() - start);

plakje

n = 1000*1000;
start = + new Date();
a = Array(n); 
b = a.slice();
console.log(new Date() - start);

Houd er rekening mee dat deze methoden het Array-object zelf zullen klonen, de inhoud van de array wordt echter door verwijzing gekopieerd en wordt niet diep gekloond.

origAr == clonedArr //returns false
origAr[0] == clonedArr[0] //returns true

Antwoord 2, autoriteit 33%

Technisch gezien is slicede snelste manier. Echtergaat nog sneller als u de 0beginindex toevoegt.

myArray.slice(0);

is sneller dan

myArray.slice();

https://web.archive. org/web/20170824010701/https://jsperf.com/cloning-arrays/3


Antwoord 3, autoriteit 19%

hoe zit het met es6 way?

arr2 = [...arr1];

Antwoord 4, autoriteit 5%

Gemakkelijkste manier om een array of object diep te klonen:

var dup_array = JSON.parse(JSON.stringify(original_array))

Antwoord 5, autoriteit 4%

var cloned_array = [].concat(target_array);

Antwoord 6, autoriteit 3%

Ik heb een korte demo samengesteld: http://jsbin.com/agugo3/edit

Mijn resultaten op Internet Explorer 8 zijn 156, 782 en 750, wat aangeeft dat slicein dit geval veel sneller is.


Antwoord 7

ECMAScript 2015-manier met de Spread-operator:

Basisvoorbeelden:

var copyOfOldArray = [...oldArray]
var twoArraysBecomeOne = [...firstArray, ..seccondArray]

Probeer het in de browserconsole:

var oldArray = [1, 2, 3]
var copyOfOldArray = [...oldArray]
console.log(oldArray)
console.log(copyOfOldArray)
var firstArray = [5, 6, 7]
var seccondArray = ["a", "b", "c"]
var twoArraysBecomOne = [...firstArray, ...seccondArray]
console.log(twoArraysBecomOne);

Referenties


Antwoord 8

Zoals @Dan zei: “Dit antwoord veroudert snel. Gebruik benchmarksom de werkelijke situatie”, is er één specifiek antwoord van jsperf dat voor zichzelf geen antwoord heeft gehad: terwijl:

var i = a.length;
while(i--) { b[i] = a[i]; }

had 960.589 ops/sec met de nummer twee a.concat()op 578.129 ops/sec, wat 60% is.

Dit is de nieuwste Firefox (40) 64 bit.


@aleclarson heeft een nieuwe, betrouwbaardere benchmark gemaakt.


Antwoord 9

Het hangt af van de browser. Als je kijkt in de blogpost Array.prototype.slice versus handmatige arraycreatie, er is een ruwe handleiding voor de prestaties van elk:

Resultaten:


Antwoord 10

Er is een veel schonere oplossing:

var srcArray = [1, 2, 3];
var clonedArray = srcArray.length === 1 ? [srcArray[0]] : Array.apply(this, srcArray);

De lengtecontrole is vereist, omdat de Array-constructor zich anders gedraagt wanneer deze wordt aangeroepen met precies één argument.


Antwoord 11

Onthoud dat .slice() niet werkt voor tweedimensionale arrays. Je hebt een functie als deze nodig:

function copy(array) {
  return array.map(function(arr) {
    return arr.slice();
  });
}

Antwoord 12

Het hangt af van de lengte van de array. Als de arraylengte <= 1.000.000 is, nemen de methoden sliceen concatongeveer dezelfde tijd in beslag. Maar als je een groter bereik geeft, wint de concat-methode.

Probeer bijvoorbeeld deze code:

var original_array = [];
for(var i = 0; i < 10000000; i ++) {
    original_array.push( Math.floor(Math.random() * 1000000 + 1));
}
function a1() {
    var dup = [];
    var start = Date.now();
    dup = original_array.slice();
    var end = Date.now();
    console.log('slice method takes ' + (end - start) + ' ms');
}
function a2() {
    var dup = [];
    var start = Date.now();
    dup = original_array.concat([]);
    var end = Date.now();
    console.log('concat method takes ' + (end - start) + ' ms');
}
function a3() {
    var dup = [];
    var start = Date.now();
    for(var i = 0; i < original_array.length; i ++) {
        dup.push(original_array[i]);
    }
    var end = Date.now();
    console.log('for loop with push method takes ' + (end - start) + ' ms');
}
function a4() {
    var dup = [];
    var start = Date.now();
    for(var i = 0; i < original_array.length; i ++) {
        dup[i] = original_array[i];
    }
    var end = Date.now();
    console.log('for loop with = method takes ' + (end - start) + ' ms');
}
function a5() {
    var dup = new Array(original_array.length)
    var start = Date.now();
    for(var i = 0; i < original_array.length; i ++) {
        dup.push(original_array[i]);
    }
    var end = Date.now();
    console.log('for loop with = method and array constructor takes ' + (end - start) + ' ms');
}
a1();
a2();
a3();
a4();
a5();

Als u de lengte van original_array instelt op 1.000.000, nemen de methode sliceen concatongeveer dezelfde tijd in beslag (3-4 ms, afhankelijk van de willekeurige cijfers).

Als je de lengte van original_array instelt op 10.000.000, dan duurt de methode slicemeer dan 60 ms en de methode concatmeer dan 20 ms.


Antwoord 13

Benchmarktijd!

function log(data) {
  document.getElementById("log").textContent += data + "\n";
}
benchmark = (() => {
  time_function = function(ms, f, num) {
    var z = 0;
    var t = new Date().getTime();
    for (z = 0;
      ((new Date().getTime() - t) < ms); z++)
      f(num);
    return (z)
  }
  function clone1(arr) {
    return arr.slice(0);
  }
  function clone2(arr) {
    return [...arr]
  }
  function clone3(arr) {
    return [].concat(arr);
  }
  Array.prototype.clone = function() {
    return this.map(e => Array.isArray(e) ? e.clone() : e);
  };
  function clone4(arr) {
    return arr.clone();
  }
  function benchmark() {
    function compare(a, b) {
      if (a[1] > b[1]) {
        return -1;
      }
      if (a[1] < b[1]) {
        return 1;
      }
      return 0;
    }
    funcs = [clone1, clone2, clone3, clone4];
    results = [];
    funcs.forEach((ff) => {
      console.log("Benchmarking: " + ff.name);
      var s = time_function(2500, ff, Array(1024));
      results.push([ff, s]);
      console.log("Score: " + s);
    })
    return results.sort(compare);
  }
  return benchmark;
})()
log("Starting benchmark...\n");
res = benchmark();
console.log("Winner: " + res[0][0].name + " !!!");
count = 1;
res.forEach((r) => {
  log((count++) + ". " + r[0].name + " score: " + Math.floor(10000 * r[1] / res[0][1]) / 100 + ((count == 2) ? "% *winner*" : "% speed of winner.") + " (" + Math.round(r[1] * 100) / 100 + ")");
});
log("\nWinner code:\n");
log(res[0][0].toString());
<textarea rows="50" cols="80" style="font-size: 16; resize:none; border: none;" id="log"></textarea>

Antwoord 14

In ES6 kun je eenvoudig de Spread syntaxis.

Voorbeeld:

let arr = ['a', 'b', 'c'];
let arr2 = [...arr];

Houd er rekening mee dat de spread-operator een volledig nieuwe array genereert, dus het wijzigen van de ene heeft geen invloed op de andere.

Voorbeeld:

arr2.push('d') // becomes ['a', 'b', 'c', 'd']
console.log(arr) // while arr retains its values ['a', 'b', 'c']

Antwoord 15

De snelste manier om een array van objecten te klonen is door de spread-operator te gebruiken

var clonedArray=[...originalArray]

maar de objecten in die gekloonde array zullen nog steeds naar de oude geheugenlocatie wijzen. vandaar dat verandering naar clonedArray-objecten ook de orignalArray zal veranderen.

var clonedArray = originalArray.map(({...ele}) => {return ele})

hiermee wordt niet alleen een nieuwe array gemaakt, maar worden ook de objecten gekloond.


Antwoord 16

Een eenvoudige oplossing:

original = [1,2,3]
cloned = original.map(x=>x)

Antwoord 17

       const arr = ['1', '2', '3'];
         // Old way
        const cloneArr = arr.slice();
        // ES6 way
        const cloneArrES6 = [...arr];
// But problem with 3rd approach is that if you are using muti-dimensional 
 // array, then only first level is copied
        const nums = [
              [1, 2], 
              [10],
         ];
        const cloneNums = [...nums];
// Let's change the first item in the first nested item in our cloned array.
        cloneNums[0][0] = '8';
        console.log(cloneNums);
           // [ [ '8', 2 ], [ 10 ], [ 300 ] ]
        // NOOooo, the original is also affected
        console.log(nums);
          // [ [ '8', 2 ], [ 10 ], [ 300 ] ]

Dus, om te voorkomen dat deze scenario’s gebeuren, gebruik

       const arr = ['1', '2', '3'];
        const cloneArr = Array.from(arr);

Antwoord 18

Er waren verschillende manieren om een array te klonen. Klonen werd in principe op twee manieren gecategoriseerd:

  1. Ondiepe kopie
  2. Diepe kopie

Ondiepe kopieën bedekken alleen het 1e niveau van de array en de rest is
verwezen. Als je een echte kopie van geneste elementen in de arrays wilt, heb je a . nodig
diepe kloon.

Voorbeeld:

const arr1 = [1,2,3,4,5,6,7]           
// Normal Array (shallow copy is enough)     
const arr2 = [1,2,3,[4],[[5]],6,7]          
// Nested Array  (Deep copy required) 
Approach 1 : Using (...)Spread Operator  (Shallow copy enough)
const newArray = [...arr1] // [1,2,3,4,5,6,7]
Approach 2 : Using Array builtIn Slice method (Deep copy)  
const newArray = arr1.slice()  // [1,2,3,4,5,6,7]
Approach 3 : Using Array builtIn Concat method (Deep a copy)
const newArray = [].concat(arr1)  // [1,2,3,4,5,6,7]
Approach 4 : Using JSON.stringify/parse. (Deep a copy & fastest)
const newArray = JSON.parse(JSON.stringify(arr2));)  // [1,2,3,[4],[[5]],6,7]
Approach 5: Using own recursive function or using loadash's __.cloneDeep method. (Deep copy)

Antwoord 19

Snelle manieren om een array in JavaScript op volgorde te dupliceren:

#1: array1copy = [...array1];

#2: array1copy = array1.slice(0);

#3: array1copy = array1.slice();

Als uw array-objecten enige JSON-niet-serializeerbare inhoud bevatten (functies, Number.POSITIVE_INFINITY, enz.), kunt u dit beter gebruiken

array1copy = JSON.parse(JSON.stringify(array1))


Antwoord 20

Je kunt deze code volgen. Onveranderlijke manier array kloon. Dit is de perfecte manier om arrays te klonen


const array = [1, 2, 3, 4]
const newArray = [...array]
newArray.push(6)
console.log(array)
console.log(newArray)

Antwoord 21

Als je een ECHT gekloond object/array in JS wilt met gekloonde verwijzingen van alle attributen en subobjecten:

export function clone(arr) {
    return JSON.parse(JSON.stringify(arr))
}

Alle andere bewerkingen maken geen klonen, omdat ze gewoon het basisadres van het root-element wijzigen, niet van de meegeleverde objecten.

behalve dat je recursief door de object-boom doorkruist.

Voor een eenvoudige kopie zijn deze OK. Voor opslagadres Relevante bewerkingen I Suggereer ik (en in de meeste andere gevallen, omdat dit snel is!) Om te typen in tekenreeks en terug in een compleet nieuw object.

Other episodes