“Estranhas Array (n)” e “Array.prototype.map” do JavaScript

Eu observei isso no Firefox-3.5.7 / Firebug-1.5.3 e no Firefox-3.6.16 / Firebug-1.6.2

Quando eu disparo no Firebug:

>>> x = new Array(3) [undefined, undefined, undefined] >>> y = [undefined, undefined, undefined] [undefined, undefined, undefined] >>> x.constructor == y.constructor true >>> x.map(function(){ return 0; }) [undefined, undefined, undefined] >>> y.map(function(){ return 0; }) [0, 0, 0] 

Oque esta acontecendo aqui? Isso é um bug, ou eu estou entendendo mal como usar o new Array(3) ?

Parece que o primeiro exemplo

 x = new Array(3); 

Cria uma matriz com pointers indefinidos.

E o segundo cria um array com pointers para 3 objects indefinidos, neste caso os pointers não são indefinidos, apenas os objects para os quais apontam.

 y = [undefined, undefined, undefined] // The following is not equivalent to the above, it's the same as new Array(3) y = [,,,]; 

Como o mapa é executado no contexto dos objects na matriz, acredito que o primeiro mapa falha ao executar a function enquanto o segundo consegue executar.

Eu tinha uma tarefa que eu só sabia o comprimento da matriz e precisava transformar os itens. Eu queria fazer algo assim:

 let arr = new Array(10).map((val,idx) => idx); 

Para criar rapidamente uma matriz como esta:

 [0,1,2,3,4,5,6,7,8,9] 

Mas não funcionou porque: veja a resposta de Jonathan Lonowski algumas respostas acima.

A solução poderia ser preencher os itens da matriz com qualquer valor (mesmo com indefinido) usando Array.prototype.fill ()

 let arr = new Array(10).fill(undefined).map((val,idx) => idx); 
 console.log(new Array(10).fill(undefined).map((val, idx) => idx)); 

Com ES6, você pode fazer [...Array(10)].map((a, b) => a) , rápido e fácil!

Da página do MDC para o map :

[…] o callback é invocado apenas para índices da matriz que tem valor atribuído; […]

[undefined] aplica o setter no (s) índice (s) para que o map seja iterado, enquanto o new Array(1) apenas inicializa o (s) índice (s) com um valor padrão de undefined então o map ignora.

Eu acredito que isso é o mesmo para todos os methods de iteração .

As matrizes são diferentes. A diferença é que o new Array(3) cria um array com um comprimento de três, mas sem propriedades, enquanto [undefined, undefined, undefined] cria um array com um comprimento de três e três propriedades chamado “0”, “1” e ” 2 “, cada um com um valor de undefined . Você pode ver a diferença usando o operador in :

 "0" in new Array(3); // false "0" in [undefined, undefined, undefined]; // true 

Isso decorre do fato ligeiramente confuso de que, se você tentar obter o valor de uma propriedade inexistente de qualquer object nativo em JavaScript, ele retornará undefined (em vez de gerar um erro, como acontece quando você tenta se referir a um erro inexistente). variável), que é o mesmo que você obtém se a propriedade tiver sido definida explicitamente como undefined .

Solução ES6:

 [...Array(10)] 

Não funciona no texto datilografado (2.3), embora

Acho que a melhor maneira de explicar isso é analisar a maneira como o Chrome lida com isso.

 >>> x = new Array(3) [] >>> x.length 3 

Então, o que está realmente acontecendo é que o novo Array () está retornando um array vazio que tem um comprimento de 3, mas nenhum valor. Portanto, quando você executa x.map em uma matriz tecnicamente vazia, não há nada a ser definido.

O Firefox apenas “preenche” esses espaços vazios com undefined mesmo que não tenha valores.

Eu não acho que isso seja explicitamente um bug, apenas uma maneira pobre de representar o que está acontecendo. Suponho que o Chrome esteja “mais correto” porque mostra que não há realmente nada na matriz.

Apenas corri para isso. Com certeza seria conveniente usar o Array(n).map .

Array(3) rende aproximadamente {length: 3}

[undefined, undefined, undefined] cria as propriedades numeradas:
{0: undefined, 1: undefined, 2: undefined, length: 3} .

A implementação map () só atua em propriedades definidas.

Na especificação da 6ª edição do ECMAScript.

new Array(3) define apenas o length propriedade e não define propriedades de índice como {length: 3} . consulte https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array-len Etapa 9.

[undefined, undefined, undefined] definirá propriedades de índice e propriedade de comprimento como {0: undefined, 1: undefined, 2: undefined, length: 3} . veja https://www.ecma-international.org/ecma-262/6.0/index.html#sec-runtime-semantics-arrayaccumulation ElementList Etapa 5.

map methods, every , some , forEach , slice , reduce , reduceRight , filter de Array irá verificar a propriedade index pelo método interno HasProperty , portanto, new Array(3).map(v => 1) não invocará o callback.

para mais detalhes, consulte https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array.prototype.map

Como consertar?

 let a = new Array(3); a.join('.').split('.').map(v => 1); let a = new Array(3); a.fill(1); let a = new Array(3); a.fill(undefined).map(v => 1); let a = new Array(3); [...a].map(v => 1); 

Não é um bug. É assim que o construtor Array é definido para funcionar.

De MDC:

Quando você especifica um único parâmetro numérico com o construtor Array, especifica o comprimento inicial da matriz. O código a seguir cria uma matriz de cinco elementos:

 var billingMethod = new Array(5); 

O comportamento do construtor Array depende se o único parâmetro é um número.

O método .map() inclui apenas nos elementos de iteração da matriz que explicitamente tinham valores atribuídos. Mesmo uma atribuição explícita de undefined fará com que um valor seja considerado elegível para inclusão na iteração. Isso parece estranho, mas é essencialmente a diferença entre uma propriedade undefined explícita em um object e uma propriedade ausente:

 var x = { }, y = { z: undefined }; if (xz === yz) // true 

O object x não possui uma propriedade chamada “z” e o object y possui. No entanto, em ambos os casos, parece que o “valor” da propriedade é undefined . Em uma matriz, a situação é semelhante: o valor de length realiza implicitamente uma atribuição de valor para todos os elementos de zero a length - 1 . A function .map() , portanto, não fará nada (não chamará o retorno de chamada) quando chamada em uma matriz recém construída com o construtor Array e um argumento numérico.

Se você estiver fazendo isso para preencher facilmente uma matriz com valores, não pode usar o preenchimento por razões de suporte ao navegador e realmente não quer fazer um loop, você também pode fazer x = new Array(3).join(".").split(".").map(... que lhe dará um array de strings vazias.

Muito feio eu tenho que dizer, mas pelo menos o problema e a intenção são comunicados com muita clareza.

No Chrome, se eu fizer o new Array(3) , recebo [] , então, meu palpite é que você se deparou com um bug do navegador.