<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>C on Arthur Cruz</title><link>https://arthcruz.dev/pt-br/tags/c/</link><description>Recent content in C on Arthur Cruz</description><generator>Hugo -- gohugo.io</generator><language>pt-br</language><lastBuildDate>Thu, 01 Oct 2026 00:00:00 -0300</lastBuildDate><atom:link href="https://arthcruz.dev/pt-br/tags/c/index.xml" rel="self" type="application/rss+xml"/><item><title>Os Arrays do JavaScript Não São Arrays</title><link>https://arthcruz.dev/pt-br/posts/javascript-arrays-are-not-arrays/</link><pubDate>Thu, 01 Oct 2026 00:00:00 -0300</pubDate><guid>https://arthcruz.dev/pt-br/posts/javascript-arrays-are-not-arrays/</guid><description>&lt;img src="https://arthcruz.dev/pt-br/posts/javascript-arrays-are-not-arrays/images/poster.pt-br.png" alt="Featured image of post Os Arrays do JavaScript Não São Arrays" />&lt;p>Toda medição e toda saída deste post foram produzidas no Node 24.16.0, V8 13.6.233.17. Os layouts de elemento da seção 7 foram inspecionados com &lt;code>node --allow-natives-syntax&lt;/code>.&lt;/p>
&lt;h2 id="1-o-que-é-um-array-e-por-que-a-definição-importa">1. O que é um array, e por que a definição importa
&lt;/h2>&lt;p>Um array, no sentido de estrutura de dados, é um bloco contíguo de memória guardando elementos de tamanho igual e conhecido. Essa única frase já carrega todo o resto:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">int&lt;/span> xs[&lt;span style="color:#ae81ff">5&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// xs[3] não é uma consulta. É aritmética:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// endereço(xs[3]) = endereço(xs) + 3 * sizeof(int)
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Como os elementos têm o mesmo tamanho e ficam um ao lado do outro, o endereço do elemento &lt;code>i&lt;/code> se calcula com uma multiplicação e uma soma. Indexar em tempo constante não é um recurso que a estrutura oferece. É consequência do layout, e é inevitável: não há o que procurar, não há o que hashear, não há o que percorrer.&lt;/p>
&lt;p>O mesmo layout força o resto do contrato. O comprimento é fixo, porque o bloco foi alocado uma vez. Todo slot tem o mesmo tamanho, porque a aritmética precisa de um passo constante. Isso em geral significa tipo uniforme, embora um array de ponteiros satisfaça a exigência apontando para coisas diferentes. Não existem vãos, porque todo byte do bloco faz parte de algum elemento, tendo você escrito nele ou não.&lt;/p>
&lt;p>Guarde essas quatro propriedades: &lt;strong>contíguo, slots de tamanho fixo, comprimento fixo, sem vãos&lt;/strong>. É isso que a palavra significa. O resto que usa o nome está usando emprestado.&lt;/p>
&lt;h2 id="2-o-que-o-javascript-te-dá-no-lugar">2. O que o JavaScript te dá no lugar
&lt;/h2>&lt;p>Na especificação do ECMAScript, um Array é um &lt;em>objeto exótico&lt;/em>: um objeto comum com um &lt;code>[[DefineOwnProperty]]&lt;/code> customizado e uma propriedade &lt;code>length&lt;/code> que se mantém sozinha. Repare no substantivo. É um objeto.&lt;/p>
&lt;p>Isso não é metáfora. Chaves de propriedade em JavaScript são de dois tipos, strings e symbols, e índices de array são sempre do primeiro tipo:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">a&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">10&lt;/span>, &lt;span style="color:#ae81ff">20&lt;/span>, &lt;span style="color:#ae81ff">30&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Object.&lt;span style="color:#a6e22e">keys&lt;/span>(&lt;span style="color:#a6e22e">a&lt;/span>); &lt;span style="color:#75715e">// [&amp;#34;0&amp;#34;, &amp;#34;1&amp;#34;, &amp;#34;2&amp;#34;]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">typeof&lt;/span> Object.&lt;span style="color:#a6e22e">keys&lt;/span>(&lt;span style="color:#a6e22e">a&lt;/span>)[&lt;span style="color:#ae81ff">0&lt;/span>]; &lt;span style="color:#75715e">// &amp;#34;string&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">a&lt;/span>[&lt;span style="color:#e6db74">&amp;#39;1&amp;#39;&lt;/span>] &lt;span style="color:#f92672">===&lt;/span> &lt;span style="color:#a6e22e">a&lt;/span>[&lt;span style="color:#ae81ff">1&lt;/span>]; &lt;span style="color:#75715e">// true
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">Reflect&lt;/span>.&lt;span style="color:#a6e22e">ownKeys&lt;/span>(&lt;span style="color:#a6e22e">a&lt;/span>); &lt;span style="color:#75715e">// [&amp;#34;0&amp;#34;, &amp;#34;1&amp;#34;, &amp;#34;2&amp;#34;, &amp;#34;length&amp;#34;]
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>a[1]&lt;/code> não é um deslocamento. É uma consulta de propriedade cuja chave por acaso é a string &lt;code>&amp;quot;1&amp;quot;&lt;/code>, e o número que você escreveu virou essa string no caminho. Não existe aritmética de endereço em lugar nenhum dessa abstração. Se alguma aritmética acontece por baixo, isso é decisão que o motor toma depois, e a seção 7 é sobre como ele decide.&lt;/p>
&lt;h2 id="3-o-índice-não-é-um-número-é-uma-string-bem-específica">3. O índice não é um número, é uma string bem específica
&lt;/h2>&lt;p>Se índices são chaves string, alguma coisa precisa decidir quais strings são índices. A especificação decide, e a regra é estreita: uma chave é índice de array quando ela é a string decimal canônica de um inteiro não negativo abaixo de 2&lt;sup>32&lt;/sup> menos 1. Canônica quer dizer que a ida e volta sobrevive, ou seja, &lt;code>String(Number(chave)) === chave&lt;/code>. Não negativo e inteiro são exigências separadas, e cada uma delas exclui um caso que parece que deveria funcionar.&lt;/p>
&lt;p>Todo o resto é propriedade comum que por acaso mora num array:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">c&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">c&lt;/span>[&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;negativo&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">c&lt;/span>[&lt;span style="color:#ae81ff">1.5&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;fracionário&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">c&lt;/span>[&lt;span style="color:#e6db74">&amp;#39;01&amp;#39;&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;zero à esquerda&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">c&lt;/span>.&lt;span style="color:#a6e22e">length&lt;/span>; &lt;span style="color:#75715e">// 3, inalterado pelas três
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>Object.&lt;span style="color:#a6e22e">keys&lt;/span>(&lt;span style="color:#a6e22e">c&lt;/span>); &lt;span style="color:#75715e">// [&amp;#34;0&amp;#34;, &amp;#34;1&amp;#34;, &amp;#34;2&amp;#34;, &amp;#34;-1&amp;#34;, &amp;#34;1.5&amp;#34;, &amp;#34;01&amp;#34;]
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Três escritas com cara de indexação, nenhuma delas indexou coisa alguma, e cada uma falha numa cláusula diferente da regra. &lt;code>-1&lt;/code> não é não negativo. &lt;code>1.5&lt;/code> não é inteiro. &lt;code>'01'&lt;/code> não é canônica, porque &lt;code>String(Number('01'))&lt;/code> é &lt;code>'1'&lt;/code>, não &lt;code>'01'&lt;/code>.&lt;/p>
&lt;p>O limite de cima é tão real quanto:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">b&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">b&lt;/span>[&lt;span style="color:#ae81ff">4294967294&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;último índice válido&amp;#39;&lt;/span>; &lt;span style="color:#75715e">// 2**32 - 2
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">b&lt;/span>[&lt;span style="color:#ae81ff">4294967295&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;não é índice&amp;#39;&lt;/span>; &lt;span style="color:#75715e">// 2**32 - 1
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">b&lt;/span>.&lt;span style="color:#a6e22e">length&lt;/span>; &lt;span style="color:#75715e">// 4294967295
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>Object.&lt;span style="color:#a6e22e">prototype&lt;/span>.&lt;span style="color:#a6e22e">hasOwnProperty&lt;/span>.&lt;span style="color:#a6e22e">call&lt;/span>(&lt;span style="color:#a6e22e">b&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;4294967295&amp;#39;&lt;/span>); &lt;span style="color:#75715e">// true, como propriedade comum
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">big&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">big&lt;/span>.&lt;span style="color:#a6e22e">length&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#f92672">**&lt;/span> &lt;span style="color:#ae81ff">32&lt;/span>; &lt;span style="color:#75715e">// RangeError: Invalid array length
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Num array de verdade o índice é um deslocamento, limitado pela alocação. Aqui ele é uma string, limitada por uma regra de especificação, e passar um a mais do limite não falha. Ele silenciosamente deixa de ser índice e vira propriedade, que é um modo de falhar bem mais estranho que um segmentation fault.&lt;/p>
&lt;h2 id="4-a-estrutura-admite-ausência">4. A estrutura admite ausência
&lt;/h2>&lt;p>Um array de verdade não pode ter vão. Todo slot é byte, e byte é sempre alguma coisa, mesmo que essa coisa seja lixo não inicializado.&lt;/p>
&lt;p>Um array de JavaScript pode estar sem um elemento inteiro, porque propriedade faltando é algo que objeto pode ter:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">d&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">delete&lt;/span> &lt;span style="color:#a6e22e">d&lt;/span>[&lt;span style="color:#ae81ff">1&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">d&lt;/span>.&lt;span style="color:#a6e22e">length&lt;/span>; &lt;span style="color:#75715e">// 3
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#66d9ef">in&lt;/span> &lt;span style="color:#a6e22e">d&lt;/span>; &lt;span style="color:#75715e">// false
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">d&lt;/span>[&lt;span style="color:#ae81ff">1&lt;/span>]; &lt;span style="color:#75715e">// undefined
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>Object.&lt;span style="color:#a6e22e">keys&lt;/span>(&lt;span style="color:#a6e22e">d&lt;/span>); &lt;span style="color:#75715e">// [&amp;#34;0&amp;#34;, &amp;#34;2&amp;#34;]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">JSON&lt;/span>.&lt;span style="color:#a6e22e">stringify&lt;/span>(&lt;span style="color:#a6e22e">d&lt;/span>); &lt;span style="color:#75715e">// &amp;#34;[1,null,3]&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>O length continua dizendo três. A chave &lt;code>&amp;quot;1&amp;quot;&lt;/code> sumiu. Ler devolve &lt;code>undefined&lt;/code>, que é exatamente o que você obteria de uma propriedade que nunca existiu, porque é isso que ela virou.&lt;/p>
&lt;p>Repare que um buraco e um &lt;code>undefined&lt;/code> guardado são estados diferentes que se leem igual:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">e&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#66d9ef">undefined&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#66d9ef">in&lt;/span> &lt;span style="color:#a6e22e">e&lt;/span>; &lt;span style="color:#75715e">// true, a propriedade existe e guarda undefined
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>E, como buraco é propriedade ausente, ler um buraco faz o que ler qualquer propriedade ausente faz: sobe a cadeia de protótipos.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">f&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">1&lt;/span>, , &lt;span style="color:#ae81ff">3&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Array.&lt;span style="color:#a6e22e">prototype&lt;/span>[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;veio do protótipo&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">f&lt;/span>[&lt;span style="color:#ae81ff">1&lt;/span>]; &lt;span style="color:#75715e">// &amp;#34;veio do protótipo&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Esse é o argumento inteiro numa linha. Nenhum array no sentido de estrutura de dados consegue resolver uma leitura consultando um objeto pai, porque não há consulta a interceptar, só aritmética.&lt;/p>
&lt;h2 id="5-length-é-um-ajuste-não-uma-medição">5. &lt;code>length&lt;/code> é um ajuste, não uma medição
&lt;/h2>&lt;p>Num array de verdade o comprimento é propriedade da alocação. Você não atribui a ele. Em JavaScript é propriedade gravável, e escrever nela é o jeito de redimensionar:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">g&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span>, &lt;span style="color:#ae81ff">4&lt;/span>, &lt;span style="color:#ae81ff">5&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">g&lt;/span>.&lt;span style="color:#a6e22e">length&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>; &lt;span style="color:#75715e">// [1, 2] os três últimos se foram
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">g&lt;/span>.&lt;span style="color:#a6e22e">length&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">5&lt;/span>; &lt;span style="color:#75715e">// [1, 2, &amp;lt;3 empty items&amp;gt;]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#ae81ff">3&lt;/span> &lt;span style="color:#66d9ef">in&lt;/span> &lt;span style="color:#a6e22e">g&lt;/span>; &lt;span style="color:#75715e">// false
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Truncar destrói dados. Estender fabrica buraco. E &lt;code>length&lt;/code> não é a quantidade de elementos, porque nada conta coisa alguma. A regra é mais estreita: escrever um índice de array igual ou acima do &lt;code>length&lt;/code> atual faz o &lt;code>length&lt;/code> virar esse índice mais um, e escrever direto no &lt;code>length&lt;/code> o deixa com o valor que você pediu.&lt;/p>
&lt;p>As duas metades importam, porque qualquer uma delas sozinha seria uma história mais bonita que a verdade:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">a&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">a&lt;/span>.&lt;span style="color:#a6e22e">length&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">100&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Object.&lt;span style="color:#a6e22e">keys&lt;/span>(&lt;span style="color:#a6e22e">a&lt;/span>).&lt;span style="color:#a6e22e">length&lt;/span>; &lt;span style="color:#75715e">// 0, cem elementos que ele nunca teve
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">b&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">b&lt;/span>.&lt;span style="color:#a6e22e">length&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>; &lt;span style="color:#75715e">// agora 1, mesmo tendo o índice 2 sido atribuído
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>É por isso que &lt;code>Object.keys(d).length&lt;/code> e &lt;code>d.length&lt;/code> discordam no instante em que existe um buraco.&lt;/p>
&lt;h2 id="6-é-objeto-então-carrega-o-que-você-pendurar">6. É objeto, então carrega o que você pendurar
&lt;/h2>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">h&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">h&lt;/span>.&lt;span style="color:#a6e22e">autor&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;arthur&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">h&lt;/span>.&lt;span style="color:#a6e22e">length&lt;/span>; &lt;span style="color:#75715e">// 2
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>Object.&lt;span style="color:#a6e22e">keys&lt;/span>(&lt;span style="color:#a6e22e">h&lt;/span>); &lt;span style="color:#75715e">// [&amp;#34;0&amp;#34;, &amp;#34;1&amp;#34;, &amp;#34;autor&amp;#34;]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">JSON&lt;/span>.&lt;span style="color:#a6e22e">stringify&lt;/span>(&lt;span style="color:#a6e22e">h&lt;/span>); &lt;span style="color:#75715e">// &amp;#34;[1,2]&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>A propriedade existe, o length ignora, e o serializador descarta. Três subsistemas, três opiniões diferentes sobre se aquilo faz parte do array.&lt;/p>
&lt;p>E o sistema de tipos, no pouco que ele é, não concorda com nenhum dos três:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">typeof&lt;/span> [&lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span>]; &lt;span style="color:#75715e">// &amp;#34;object&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>Array.&lt;span style="color:#a6e22e">isArray&lt;/span>([&lt;span style="color:#ae81ff">1&lt;/span>,&lt;span style="color:#ae81ff">2&lt;/span>,&lt;span style="color:#ae81ff">3&lt;/span>]); &lt;span style="color:#75715e">// true
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>Array.isArray&lt;/code> existe justamente porque &lt;code>typeof&lt;/code> não sabe responder. Não existe tipo array para reportar.&lt;/p>
&lt;h2 id="7-então-por-que-é-rápido-porque-o-motor-mente-por-você">7. Então por que é rápido? Porque o motor mente por você
&lt;/h2>&lt;p>Tudo acima descreve um dicionário com regras. Se os motores implementassem isso ao pé da letra, código com array seria inutilizável de tão lento. Eles não implementam. O V8 rastreia o que ele chama de &lt;strong>elements kind&lt;/strong> de cada array e escolhe uma representação compatível.&lt;/p>
&lt;p>Os kinds formam uma escada do mais específico para o mais geral, e as transições são visíveis:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">a&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span>]; &lt;span style="color:#75715e">// PACKED_SMI_ELEMENTS
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">a&lt;/span>.&lt;span style="color:#a6e22e">push&lt;/span>(&lt;span style="color:#ae81ff">4.5&lt;/span>); &lt;span style="color:#75715e">// PACKED_DOUBLE_ELEMENTS
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">a&lt;/span>.&lt;span style="color:#a6e22e">push&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;texto&amp;#39;&lt;/span>); &lt;span style="color:#75715e">// PACKED_ELEMENTS
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Cada degrau amplia o que um slot pode guardar, e cada degrau custa algo. O caso de inteiro pequeno empacotado guarda inteiros pequenos com tag direto num armazenamento contíguo, que é um array de verdade no sentido da seção 1. O caso de double empacotado guarda doubles sem boxing. O caso geral usa slots com tag que aceitam os dois: um inteiro pequeno continua cabendo no próprio slot, e qualquer outra coisa vira referência para o heap.&lt;/p>
&lt;p>Um segundo eixo rastreia se buracos são possíveis:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>o que você escreveu&lt;/th>
&lt;th>kind resultante&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>[1, 2, 3]&lt;/code>&lt;/td>
&lt;td>&lt;code>PACKED_SMI&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>[1.1, 2.2]&lt;/code>&lt;/td>
&lt;td>&lt;code>PACKED_DOUBLE&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>[]&lt;/code>&lt;/td>
&lt;td>&lt;code>PACKED_SMI&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>new Array(3)&lt;/code>&lt;/td>
&lt;td>&lt;code>HOLEY_SMI&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>[1,2,3]&lt;/code> e depois &lt;code>delete a[1]&lt;/code>&lt;/td>
&lt;td>&lt;code>HOLEY_SMI&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>[1,2,3]&lt;/code> e depois &lt;code>a[10] = 4&lt;/code>&lt;/td>
&lt;td>&lt;code>HOLEY_SMI&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>[1,2,3]&lt;/code> e depois &lt;code>a[100000] = 1&lt;/code>&lt;/td>
&lt;td>&lt;code>DICTIONARY_ELEMENTS&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Representações com buraco precisam checar, a cada leitura, se o slot é um buraco, e, se for, recorrer à cadeia de protótipos da seção 4. O modo dicionário abandona o buffer de vez e guarda os elementos numa tabela hash, que é bem mais próximo da consulta de propriedade que a especificação de fato descreve.&lt;/p>
&lt;p>As transições não se revertem sozinhas. Remover o elemento que causou a mudança não restaura a representação anterior:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">h&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">1.5&lt;/span>, &lt;span style="color:#ae81ff">2.5&lt;/span>, &lt;span style="color:#ae81ff">3.5&lt;/span>]; &lt;span style="color:#75715e">// PACKED_DOUBLE
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">h&lt;/span>.&lt;span style="color:#a6e22e">push&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;x&amp;#39;&lt;/span>); &lt;span style="color:#75715e">// PACKED_ELEMENTS
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">h&lt;/span>.&lt;span style="color:#a6e22e">pop&lt;/span>(); &lt;span style="color:#75715e">// continua PACKED_ELEMENTS
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Só que elas não são estritamente de mão única. Uma operação que reescreve todos os slots pode produzir um kind mais estreito, e o &lt;code>fill&lt;/code> é o caso mais claro no V8 atual. Ele leva um array com buraco de volta para empacotado, e na minha medição levou um &lt;code>PACKED_ELEMENTS&lt;/code> de volta até &lt;code>PACKED_SMI&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">a&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span>];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">delete&lt;/span> &lt;span style="color:#a6e22e">a&lt;/span>[&lt;span style="color:#ae81ff">1&lt;/span>]; &lt;span style="color:#75715e">// HOLEY_SMI
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">a&lt;/span>.&lt;span style="color:#a6e22e">fill&lt;/span>(&lt;span style="color:#ae81ff">0&lt;/span>); &lt;span style="color:#75715e">// PACKED_SMI, descendo a escada de novo
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Então a formulação útil não é que a escada é de mão única, é que você nunca desce de volta por acidente. Alargar acontece como efeito colateral de escritas comuns; estreitar exige uma operação que reescreve o armazenamento inteiro.&lt;/p>
&lt;p>Essa é a resposta de verdade para o título. O array que você acha que está usando é uma representação que o motor te concede enquanto seu uso fica dentro de um conjunto de suposições, e revoga em silêncio quando não fica. A especificação promete um objeto com length que se mantém sozinho. O buffer contíguo é otimização, não garantia.&lt;/p>
&lt;h2 id="8-o-precipício-medido">8. O precipício, medido
&lt;/h2>&lt;p>Três arrays de 100.000 inteiros, conteúdo idêntico e comprimento idêntico, diferindo só no elements kind. Somando cada um com um &lt;code>for&lt;/code> indexado simples, 100 rodadas de aquecimento, mediana de 51 rodadas medidas:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>elements kind&lt;/th>
&lt;th>mediana&lt;/th>
&lt;th>relativo&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>PACKED_SMI&lt;/code>&lt;/td>
&lt;td>0,053 ms&lt;/td>
&lt;td>1x&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>HOLEY_SMI&lt;/code>&lt;/td>
&lt;td>0,080 ms&lt;/td>
&lt;td>cerca de 1,2x a 1,5x entre execuções&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>DICTIONARY&lt;/code>&lt;/td>
&lt;td>2,94 ms&lt;/td>
&lt;td>cerca de 43x a 56x entre execuções&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>A penalidade do buraco é real, mas modesta, e variou o bastante entre execuções para eu não cravar um multiplicador. A penalidade do dicionário não é modesta e não variou: é a diferença entre aritmética e hash, nos mesmos dados, no mesmo laço.&lt;/p>
&lt;p>O que produziu o caso dicionário merece ser encarado. Foi uma atribuição:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">a&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">for&lt;/span> (&lt;span style="color:#66d9ef">let&lt;/span> &lt;span style="color:#a6e22e">i&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>; &lt;span style="color:#a6e22e">i&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#ae81ff">100000&lt;/span>; &lt;span style="color:#a6e22e">i&lt;/span>&lt;span style="color:#f92672">++&lt;/span>) &lt;span style="color:#a6e22e">a&lt;/span>.&lt;span style="color:#a6e22e">push&lt;/span>(&lt;span style="color:#a6e22e">i&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">a&lt;/span>[&lt;span style="color:#ae81ff">5000000&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>; &lt;span style="color:#75715e">// um índice bem além do fim
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">a&lt;/span>.&lt;span style="color:#a6e22e">length&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">100000&lt;/span>; &lt;span style="color:#75715e">// desfazer não restaura a representação
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Uma única escrita num índice distante converteu um buffer contíguo em tabela hash, e o array seguiu com toda a aparência de array rodando cinquenta vezes mais devagar.&lt;/p>
&lt;h2 id="9-o-array-de-verdade-se-escreve-diferente">9. O array de verdade se escreve diferente
&lt;/h2>&lt;p>O JavaScript tem sim a estrutura da seção 1. Ela tem outro nome:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">t&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> &lt;span style="color:#a6e22e">Int32Array&lt;/span>(&lt;span style="color:#ae81ff">3&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">t&lt;/span>.&lt;span style="color:#a6e22e">BYTES_PER_ELEMENT&lt;/span>; &lt;span style="color:#75715e">// 4
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">t&lt;/span>.&lt;span style="color:#a6e22e">buffer&lt;/span>.&lt;span style="color:#a6e22e">byteLength&lt;/span>; &lt;span style="color:#75715e">// 12, exatamente 3 * 4
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">t&lt;/span>[&lt;span style="color:#ae81ff">5&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">99&lt;/span>; &lt;span style="color:#75715e">// fora dos limites: descartado
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">t&lt;/span>[&lt;span style="color:#ae81ff">5&lt;/span>]; &lt;span style="color:#75715e">// undefined
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>Object.&lt;span style="color:#a6e22e">prototype&lt;/span>.&lt;span style="color:#a6e22e">hasOwnProperty&lt;/span>.&lt;span style="color:#a6e22e">call&lt;/span>(&lt;span style="color:#a6e22e">t&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;5&amp;#39;&lt;/span>); &lt;span style="color:#75715e">// false, nenhuma propriedade foi criada
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">t&lt;/span>.&lt;span style="color:#a6e22e">length&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">10&lt;/span>; &lt;span style="color:#75715e">// TypeError em modo estrito: length só tem getter
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Comprimento fixo, tipo de elemento uniforme, buffer contíguo por trás, e escrita fora dos limites é descartada em vez de virar propriedade. Doze bytes, três inteiros, aritmética de endereço. Isso é um array.&lt;/p>
&lt;p>Uma ressalva sobre &amp;ldquo;fixo&amp;rdquo;. Desde o &lt;code>ArrayBuffer&lt;/code> redimensionável, um typed array construído sobre um buffer redimensionável acompanha esse buffer, e o comprimento dele muda quando o buffer muda:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">rab&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> &lt;span style="color:#a6e22e">ArrayBuffer&lt;/span>(&lt;span style="color:#ae81ff">8&lt;/span>, { &lt;span style="color:#a6e22e">maxByteLength&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#ae81ff">64&lt;/span> });
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">t&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> &lt;span style="color:#a6e22e">Int32Array&lt;/span>(&lt;span style="color:#a6e22e">rab&lt;/span>); &lt;span style="color:#75715e">// t.length é 2
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">rab&lt;/span>.&lt;span style="color:#a6e22e">resize&lt;/span>(&lt;span style="color:#ae81ff">32&lt;/span>); &lt;span style="color:#75715e">// t.length agora é 8
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>O &lt;code>new Int32Array(3)&lt;/code> do exemplo acima não faz isso. O buffer dele não é redimensionável, então o comprimento fica decidido na construção.&lt;/p>
&lt;p>Continua sendo objeto, e continua aceitando o que você pendurar (&lt;code>t.foo = 'bar'&lt;/code> funciona). Mas a parte &lt;em>indexada&lt;/em> deixou de ser negociável, e é aí que mora toda a diferença.&lt;/p>
&lt;h2 id="10-o-que-decorre-disso-na-prática">10. O que decorre disso na prática
&lt;/h2>&lt;p>Tudo abaixo foi medido do mesmo jeito, e é o que o argumento deixa de prático:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>construção&lt;/th>
&lt;th>kind resultante&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>[]&lt;/code> e &lt;code>push&lt;/code> num laço&lt;/td>
&lt;td>&lt;code>PACKED_SMI&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>new Array(3)&lt;/code>&lt;/td>
&lt;td>&lt;code>HOLEY_SMI&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>new Array(3).fill(0)&lt;/code>&lt;/td>
&lt;td>&lt;code>PACKED_SMI&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Array.from({length: 3}, (_, i) =&amp;gt; i)&lt;/code>&lt;/td>
&lt;td>&lt;code>PACKED_SMI&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>[1,2,3]&lt;/code> e depois &lt;code>splice(1, 1)&lt;/code>&lt;/td>
&lt;td>&lt;code>PACKED_SMI&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>[1,2,3]&lt;/code> e depois &lt;code>delete a[1]&lt;/code>&lt;/td>
&lt;td>&lt;code>HOLEY_SMI&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>map&lt;/code> sobre array com buraco&lt;/td>
&lt;td>&lt;code>HOLEY_SMI&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>filter&lt;/code> sobre array com buraco&lt;/td>
&lt;td>&lt;code>HOLEY_SMI&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Quatro coisas decorrem daí, em ordem decrescente de importância:&lt;/p>
&lt;p>&lt;strong>Nunca escreva muito além do fim.&lt;/strong> É a única com modo de falha catastrófico, e a seção 8 mediu. Todo o resto desta lista custa uma fração; essa custa uma ordem de grandeza, e sobrevive à remoção do que a causou.&lt;/p>
&lt;p>&lt;strong>Remova com &lt;code>splice&lt;/code> ou &lt;code>pop&lt;/code>, não com &lt;code>delete&lt;/code>.&lt;/strong> &lt;code>delete&lt;/code> abre buraco por definição: ele remove uma propriedade. &lt;code>splice&lt;/code> reindexa e mantém o array empacotado.&lt;/p>
&lt;p>&lt;strong>Se for pré-dimensionar, preencha.&lt;/strong> &lt;code>new Array(n)&lt;/code> já nasce com buraco. &lt;code>new Array(n).fill(0)&lt;/code> e &lt;code>Array.from({length: n}, fn)&lt;/code> não.&lt;/p>
&lt;p>&lt;strong>Buraco se propaga.&lt;/strong> &lt;code>map&lt;/code> e &lt;code>filter&lt;/code> sobre array com buraco devolvem array com buraco, mesmo o &lt;code>filter&lt;/code> descartando os buracos. Se um buraco entra cedo nos seus dados, ele viaja.&lt;/p>
&lt;p>E uma calibragem, porque esse assunto atrai folclore: na medição acima, buraco custou algo entre vinte e cinquenta por cento num laço de soma apertado. Vale evitar, não vale reescrever código em pânico. Modo dicionário é o que se deve temer de fato.&lt;/p>
&lt;h2 id="11-conclusão">11. Conclusão
&lt;/h2>&lt;p>O nome é o problema. &amp;ldquo;Array&amp;rdquo; importa uma expectativa de memória contígua, indexação em tempo constante por aritmética, slots de tamanho fixo e comprimento fixo, e o JavaScript nunca prometeu nenhuma das quatro. O que a linguagem define é um objeto cujas chaves string com cara de inteiro recebem tratamento especial e cujo &lt;code>length&lt;/code> se mantém sozinho.&lt;/p>
&lt;p>O fato de ele se comportar como array mesmo assim é trabalho do motor, não da linguagem, e o motor faz isso condicionalmente. Cada esquisitice das seções 3 a 6 não é uma verruga num array. É o objeto aparecendo por baixo, que é o que estava ali desde sempre.&lt;/p>
&lt;p>O valor prático de saber disso não é microotimização. É que os comportamentos deixam de ser surpresa. Um buraco resolvido pela cadeia de protótipos, um &lt;code>length&lt;/code> que discorda do &lt;code>Object.keys&lt;/code>, um índice que silenciosamente vira propriedade, uma lentidão de cinquenta vezes sem causa visível: nada disso é anomalia para decorar depois que você sabe que está segurando um objeto que finge, com competência e condicionalmente, ser um array.&lt;/p>
&lt;h2 id="12-referências">12. Referências
&lt;/h2>&lt;ul>
&lt;li>&lt;a class="link" href="https://tc39.es/ecma262/#sec-array-exotic-objects" target="_blank" rel="noopener"
>Especificação do ECMAScript: Array Exotic Objects&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array" target="_blank" rel="noopener"
>MDN: Array&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://v8.dev/blog/elements-kinds" target="_blank" rel="noopener"
>Blog do V8: elements kinds in V8&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/TypedArray" target="_blank" rel="noopener"
>MDN: TypedArray&lt;/a>&lt;/li>
&lt;/ul></description></item></channel></rss>