Por que posso adicionar propriedades nomeadas a uma matriz como se fosse um objeto?

105

Os seguintes dois snippets de código diferentes parecem equivalentes para mim:

var myArray = Array();
myArray['A'] = "Athens";
myArray['B'] = "Berlin";

e

var myObject = {'A': 'Athens', 'B':'Berlin'};

porque ambos se comportam da mesma forma, e também typeof(myArray) == typeof(myObjects)(ambos produzem 'objeto').

Existe alguma diferença entre essas variantes?

Prinzdezibel
fonte

Respostas:

131

Praticamente tudo em javascript é um objeto, então você pode "abusar" de um objeto Array definindo propriedades arbitrárias nele. Porém, isso deve ser considerado prejudicial . Matrizes são para dados indexados numericamente - para chaves não numéricas, use um objeto.

Aqui está um exemplo mais concreto de por que as chaves não numéricas não "cabem" em um Array:

var myArray = Array();
myArray['A'] = "Athens";
myArray['B'] = "Berlin";

alert(myArray.length);

Isso não exibirá '2', mas '0' - efetivamente, nenhum elemento foi adicionado ao array, apenas algumas novas propriedades adicionadas ao objeto do array.

Paul Dixon
fonte
4
myArray.length retorna um índice / chave numérico do último elemento na matriz, mas não o número real de elementos. As propriedades do objeto Array não são iguais aos valores da matriz?
Dasha Salo
1
Eu estava apenas tentando ilustrar que a semântica pretendida do objeto Array é abusada se você apenas tratá-lo como um objeto normal. No entanto, o artigo vinculado faz um trabalho melhor :)
Paul Dixon
13
A próxima vez que alguém disser que JavaScript é uma boa linguagem para desenvolver, mostrarei a ele este exemplo. Obrigado.
Olivier Pons
@Olivier, o que você chama de "bug" também pode ser um "recurso" incrível. Você pode adicionar um til e descrição de matrizes sem afetar seu conteúdo ou comprimento e sem ter que envolvê-los em objetos com title, descriptione itemspropriedades. Tudo depende de quão bem você conhece o idioma e de como o usa.
tao
Usar propriedades personalizadas em Arrays não é inerentemente errado. O que há de errado é esperar que eles ajam como membros da matriz assim que você fizer isso. Eles são propriedades de matriz, não membros, portanto, não são afetados por métodos de matriz. Isso é realmente dito pelo autor do artigo vinculado acima, nos comentários. Agora, com toda a justiça, eu desaconselho isso como uma prática, pois provavelmente confundirá muito as pessoas que usam seu código. Ou, se eles estão apenas começando, isso os colocará em um caminho perigoso, pelo poder do exemplo. Mas eu não diria que JavaScript é ruim porque permite coisas que a maioria não espera que sejam permitidas.
tao
14

Em JS arrays são objetos, apenas ligeiramente modificados (com mais algumas funções).

Funções como:

concat
every   
filer
forEach
join
indexOf
lastIndexOf
map
pop
push
reverse
shift
slice
some
sort
splice
toSource
toString
unshift
valueOf 
Casey
fonte
Embora eu não ache que todas as funções listadas sejam integradas a cada implementação de JS, você entendeu. A outra diferença seria um protótipo diferente (o que está implícito nessas funções extras).
Rashack
6

Eu penso, sou muito metafórico e enigmático com a resposta anterior. O esclarecimento segue.

Uma instância de Array, Boolean, Date, Function, Number, RegExp, String é um objeto, mas aprimorado com métodos e propriedades específicos para cada tipo. Por exemplo, uma matriz tem uma lengthpropriedade predefinida , enquanto objetos genéricos não.

javascript:alert([].length+'\n'+{}.length)

monitores

0
Indefinido

Intrinsecamente, o interpretador FF Gecko também distingue entre Arrays e Objetos genéricos com diferenças distintas avaliando construções de linguagem.

javascript:
  ra=[  "one",   "two",   "three"]; ra.a=4;
  ob={0:"one", 1:"two", 2:"three"}; ob.a=4;
  alert(
    ra            +"\n\n"+
    ob            +"\n\n"+
    ra.toSource() +"\n\n"+
    ra.a          +"\t .toSource() forgot me! \n\n"+
    ra.length     +"\t and my length! \n\n"+
    ob.toSource());
  ps=""; for(i in ra)ps+=i+" "; alert(ps);  /* NB .length is missing! */
  ps=""; for(i in ob)ps+=i+" "; alert(ps);

exibindo

um dois três

[objeto objeto]

["um dois três"]

4 .toSource () me esqueceu! 

3 e meu comprimento! 

({0: "um", 1: "dois", 2: "três", a: 4})

e 0 1 2 ae 0 1 2 a.

Em relação à declaração de que todos os objetos são funções:

Não é sintaticamente nem semanticamente correto usar uma instância de objeto arbitrário como uma função como 123()ou "abc"()ou []()ou {}()ou obj()ondeobj é qualquer tipo diferente de Function, então um objeto arbitrário INSTÂNCIA não é a Function. No entanto, dado um objeto obje seu tipo como Array, Boolean, Date, ..., como objveio a ser como um Array, Boolean, Date, ...? O que é um Array, Boolean, Date, ...?

javascript:
    alert([Array, Boolean, Date, Function, 
              Number, Object, RegExp, String] . join('\n\n') );

monitores

function Array() {
    [native code]
}

function Boolean() {
    [native code]
}

function Date() {
    [native code]
}

function Function() {
    [native code]
}

function Number() {
    [native code]
}

function Object() {
    [native code]
}

function RegExp() {
    [native code]
}

function String() {
    [native code]
}

Em todos os casos, sem equívocos, o tipo de objeto se manifesta como uma functiondefinição, daí a afirmação de que todos os objetos são funções! (A ironia é que eu intencionalmente obscureci e borrou a distinção de uma instância de objeto com a de seu tipo! Ainda assim, isso mostra "você não pode ter um sem o outro", Objeto e Função! A capitalização enfatiza o tipo como oposto a instância.)

Tanto um paradigma funcional quanto um de objeto parecem ser fundamentais para a programação e implementação dos primitivos integrados de baixo nível do interpretador JS, como Math e JSONe true.

 javascript:alert([Math, JSON, true.toSource()].join("\n\n"));

monitores

[object Math]

[object JSON]

(new Boolean(true))

Na época do desenvolvimento do Javascript, um estilo de programação centrado em objetos (OOP's - estilo de programação orientada a objetos - o "s" é meu próprio trocadilho!) Estava em voga e o interpretador foi batizado de forma semelhante com Java para dar-lhe maior credibilidade . Técnicas de programação funcional foram relegadas a exames mais abstratos e esotéricos estudando as teorias de autômatos, funções recursivas, linguagens formais, etc. e, como tal, não são palatáveis. No entanto, os pontos fortes dessas considerações formais são claramente manifestos em Javascript, particularmente conforme implementado no motor Gecko do FF (isto é .toSource()).


A definição de objeto para Função é particularmente satisfatória porque é definida como uma relação de recorrência! definido usando sua própria definição!

function Function() { [native code] }
e uma vez que uma função é um objeto, o mesmo sentimento vale para
function Object() { [native code] } .

A maioria das outras definições silencia para um valor terminal estático. Contudo,eval() é um primitivo particularmente poderoso e, portanto, uma String também pode incorporar uma funcionalidade arbitrária.

Observe novamente, o vernáculo usado acima obscurece o tipo de objeto e distinção de instância.

Ekim
fonte
5

Tudo em JavaScript é um objeto além dos tipos primitivos.

O código

var myArray = Array();

cria uma instância do objeto Array enquanto

var myObject = {'A': 'Athens', 'B':'Berlin'};

cria uma instância do objeto Object.

Tente o seguinte código

alert(myArray.constructor)
alert(myObject.constructor)

Você verá que a diferença está no tipo de construtor de objeto.

A instância do objeto Array conterá todas as propriedades e métodos do protótipo Array.

Dasha Salo
fonte
2

A diferença entre os arrays e os outros objetos em JavaScript. Embora os arrays tenham uma propriedade de comprimento que se atualiza magicamente, para objetos diferentes dos arrays não há como implementar tal propriedade.

var arrName = [];
arrName[5] = "test";
arrName.length; // <- 6

Array é usado para armazenar coisas com um índice ordinal - use-o como um array tradicional, pilha ou fila. Um objeto é um hash - use-o para dados que tenham uma chave distinta.

Parth Raval
fonte
2

Você pode adicionar propriedades nomeadas a quase tudo em javascript, mas isso não significa que você deve. Arrayem javascript deve ser usado como uma lista, se você quiser um uso de array associativoObject .

Esteja ciente de que se você realmente quiser usar um Arraycom propriedades nomeadas em vez de Objectessas propriedades não serão acessíveis em um for...ofloop e você também poderá obter resultados inesperados ao codificá-lo em JSON para passá-lo. Veja o exemplo abaixo onde todos os índices não numéricos são ignorados:

let arr = [];
let obj = {};

arr['name'] = 'John';
obj['name'] = 'John';

console.log(arr);    // will output [name: "John"]
console.log(obj);    // will output {name: "John"}

JSON.stringify(arr); // will return [] <- not what you expected
JSON.stringify(obj); // will return {"name":"John"}
resu
fonte
-1

A {}-notação é apenas um açúcar sintático para tornar o código mais agradável ;-)

JavaScript tem muitas construções semelhantes, como a construção de funções, onde function () é apenas um sinônimo para

var Func = new Function("<params>", "<code>");
Dario
fonte
3
Construtor de função NÃO é um sinônimo para o literal de função. O literal tem escopo léxico, enquanto o construtor é global. {}é a notação de objeto literal, []é um array literal, não tenho certeza de qual é o ponto de sua resposta.
Juan Mendes
Além disso, as funções declaradas estão disponíveis antes que qualquer código seja executado, as atribuições usando o construtor Function não estão disponíveis até que o código que as cria seja executado.
RobG