𝗥𝗲𝘀𝗲𝗮𝗿𝗰𝗵 𝗔𝗻𝗱 𝗥𝗲𝘀𝘂𝗹𝘁𝘀
Pelos fatos, um teste de desempenho no jsperf e a verificação de algumas coisas no console são realizados. Para a pesquisa, é utilizado o site irt.org . Abaixo está uma coleção de todas essas fontes reunidas, além de uma função de exemplo na parte inferior.
╔═══════════════╦══════╦═════════════════╦════════ ═══════╦═════════╦══════════╗
║ Método ║Concat║slice & push.apply ║ push.apply x2 ║ ForLoop ║Spread ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ mOps / Sec ║179 ║104 ║ 76 ║ 81 ║28 ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ Matrizes esparsas SIM! ║Só o fatiado ║ não ║ Talvez 2 ║ não ║
║ mantido esparso ║ ║ matriz (1º arg) ║ ║ ║ ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ Suporte ║ MSIE 4 ║ MSIE 5.5 ║ MSIE 5.5 ║ MSIE 4 ║ Borda 12 ║Source
( fonte ) ║NNav 4║NNav 4.06 ║ NNav 4.06 ║ NNav 3 ║ MSIE NNav ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║Atores de raio ║ não ║Só o empurrado ║ SIM! ! SIM! HaveSe tiver ║
Como uma matriz, matriz (2º argumento) eiterador 1 ║
╚═══════════════╩══════╩═════════════════╩════════ ═══════╩═════════╩══════════╝
1 Se o objeto do tipo matriz não tiver um propriedade Symbol.iterator , tente
espalhá-lo lançará uma exceção.
2 Depende do código. O código de exemplo a seguir "YES" preserva a escassez.
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;
}
Como visto acima, eu argumentaria que o Concat é quase sempre o caminho a seguir tanto para o desempenho quanto para a capacidade de manter a escassez de matrizes sobressalentes. Em seguida, para curtidas de matriz (como DOMNodeLists comodocument.body.children
), eu recomendaria usar o loop for porque é o segundo melhor desempenho e o único outro método que retém matrizes esparsas. Abaixo, abordaremos rapidamente o que se entende por matrizes esparsas e curtidas de matrizes para esclarecer a confusão.
𝗧𝗵𝗲 𝗙𝘂𝘁𝘂𝗿𝗲
No começo, algumas pessoas podem pensar que isso é um acaso e que os fornecedores de navegadores acabarão otimizando o Array.prototype.push para serem rápidos o suficiente para vencer o Array.prototype.concat. ERRADO! Array.prototype.concat sempre será mais rápido (pelo menos em princípio), porque é uma cópia-e-colar simples sobre os dados. Abaixo está um diagrama persuado-visual simplificado de como pode ser uma implementação de matriz de 32 bits (observe que implementações reais são MUITO mais complicadas)
Byte ║ Dados aqui
═════╬═══════════
0x00 ║ int nonNumericPropertiesLength = 0x00000000
0x01 id ibid
0x02 ║ ibid
0x03 id ibid
0x00 ║ comprimento int = 0x00000001
0x01 id ibid
0x02 ║ ibid
0x03 id ibid
0x00 value int valueIndex = 0x00000000
0x01 id ibid
0x02 ║ ibid
0x03 id ibid
0x00 ║ int valueType = JS_PRIMITIVE_NUMBER
0x01 id ibid
0x02 ║ ibid
0x03 id ibid
0x00 ║ uintptr_t valuePointer = 0x38d9eb60 (ou onde quer que esteja na memória)
0x01 id ibid
0x02 ║ ibid
0x03 id ibid
Como visto acima, tudo o que você precisa fazer para copiar algo assim é quase tão simples quanto copiá-lo byte por byte. Com Array.prototype.push.apply, é muito mais do que uma simples copiar e colar sobre os dados. O ".apply" deve verificar cada índice na matriz e convertê-lo em um conjunto de argumentos antes de passá-lo para Array.prototype.push. Em seguida, o Array.prototype.push precisa alocar adicionalmente mais memória a cada vez e (para algumas implementações de navegador) talvez até recalcular alguns dados de pesquisa de posição quanto à escassez.
Uma maneira alternativa de pensar nisso é essa. A matriz de origem 1 é uma grande pilha de papéis grampeados. A matriz de origem dois também é outra grande pilha de papéis. Seria mais rápido para você
- Vá para a loja, compre papel suficiente para obter uma cópia de cada matriz de origem. Em seguida, coloque as pilhas de papel de cada matriz de origem em uma copiadora e grampeie as duas cópias resultantes juntas.
- Vá para a loja, compre papel suficiente para uma única cópia da primeira matriz de origem. Em seguida, copie a matriz de origem para o novo papel manualmente, garantindo o preenchimento de quaisquer pontos esparsos em branco. Depois, volte para a loja, compre papel suficiente para a segunda matriz de origem. Em seguida, percorra a segunda matriz de origem e copie-a, garantindo que não haja espaços em branco na cópia. Depois, grampeie todos os papéis copiados.
Na analogia acima, a opção 1 representa Array.prototype.concat, enquanto a 2 representa Array.prototype.push.apply. Vamos testar isso com um JSperf semelhante, diferindo apenas no fato de este testar os métodos em matrizes esparsas, e não sólidas. Pode-se encontrar aqui .
Portanto, descubro que o futuro do desempenho desse caso de uso específico não está em Array.prototype.push, mas em Array.prototype.concat.
𝗖𝗹𝗮𝗿𝗶𝗳𝗶𝗰𝗮𝘁𝗶𝗼𝗻𝘀
𝗦𝗽𝗮𝗿𝗲 𝗔𝗿𝗿𝗮𝘆𝘀
Quando certos membros da matriz estão simplesmente ausentes. Por exemplo:
// 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]);
Como alternativa, o javascript permite inicializar matrizes sobressalentes facilmente.
var mySparseArray = ["foo",,,,,,,,,,undefined,{},10,,,,,"bar"];
𝗔𝗿𝗿𝗮𝘆-𝗟𝗶𝗸𝗲𝘀
Um tipo de matriz é um objeto que possui pelo menos uma length
propriedade, mas não foi inicializado com new Array
ou []
; Por exemplo, os objetos abaixo são classificados como de matriz.
{0: "foo", 1: "bar", comprimento: 2}
document.body.children
novo Uint8Array (3)
- É semelhante a um array porque, embora seja um array (digitado), coagir para um array altera o construtor.
(function () {argumentos de retorno}) ()
Observe o que acontece usando um método que coage gostos de matrizes em matrizes como fatia.
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}() ));
- NOTA: Não é recomendável chamar fatia nos argumentos da função devido ao desempenho.
Observe o que acontece usando um método que não coage gostos de matrizes em matrizes como concat.
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}() ));