¿Por qué puedo agregar propiedades con nombre a una matriz como si fuera un objeto?

105

Los siguientes dos fragmentos de código diferentes me parecen equivalentes:

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

y

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

porque ambos se comportan igual, y también typeof(myArray) == typeof(myObjects)(ambos producen 'objeto').

¿Existe alguna diferencia entre estas variantes?

prinzdezibel
fuente

Respuestas:

131

Prácticamente todo en javascript es un objeto, por lo que puede "abusar" de un objeto Array estableciendo propiedades arbitrarias en él. Sin embargo, esto debe considerarse perjudicial . Las matrices son para datos indexados numéricamente; para teclas no numéricas, use un objeto.

Aquí hay un ejemplo más concreto de por qué las teclas no numéricas no "encajan" en una matriz:

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

alert(myArray.length);

Esto no mostrará '2', sino '0'; efectivamente, no se han agregado elementos a la matriz, solo algunas propiedades nuevas agregadas al objeto de matriz.

Paul Dixon
fuente
4
myArray.length devuelve un índice / clave numérico del último elemento de la matriz, pero no el número real de elementos. ¿Las propiedades del objeto Array no son las mismas que los valores de la matriz?
Dasha Salo
1
Solo estaba tratando de ilustrar que la semántica prevista del objeto Array se abusa si simplemente lo trata como un objeto normal. Sin embargo, el artículo vinculado hace un mejor trabajo :)
Paul Dixon
13
La próxima vez que alguien diga que JavaScript es un buen lenguaje para desarrollar, le mostraré esta muestra. Gracias.
Olivier Pons
@Olivier, lo que llamas un "error" también puede ser una "característica" increíble. Puede añadir una tilde y la descripción de las matrices sin afectar su contenido o la duración y sin tener que envolverlos en objetos con title, descriptiony itemspropiedades. Todo depende de qué tan bien conozca el idioma y cómo lo use.
tao
El uso de propiedades personalizadas en matrices no es intrínsecamente incorrecto. Lo que está mal es esperar que actúen como miembros de la matriz una vez que lo haga. Son propiedades de matriz, no miembros, por lo que no se ven afectadas por los métodos de matriz. En realidad, esto lo dice el autor del artículo vinculado anteriormente, en los comentarios. Ahora, para ser justos, lo desaconsejaría como práctica, ya que probablemente confundirá muchísimo a las personas que usan su código. O, si recién están comenzando, los pondrá en un camino peligroso, por el poder del ejemplo. Pero no diría que JavaScript es malo porque permite cosas que la mayoría no espera que estén permitidas.
tao
14

En JS, las matrices son objetos, ligeramente modificados (con algunas funciones más).

Funciones como:

concat
every   
filer
forEach
join
indexOf
lastIndexOf
map
pop
push
reverse
shift
slice
some
sort
splice
toSource
toString
unshift
valueOf 
Casey
fuente
Aunque no creo que todas las funciones enumeradas estén integradas en cada implementación de JS, entendiste el punto. La otra diferencia sería un prototipo diferente (que está implícito en esas funciones adicionales).
Rashack
6

Yo pienso, yo demasiado metafórico y críptico con respuesta anterior. Sigue la aclaración.

Una instancia de Array, Boolean, Date, Function, Number, RegExp, String es un objeto pero mejorado con métodos y propiedades específicos de cada tipo. Por ejemplo, una matriz tiene una lengthpropiedad predefinida , mientras que los objetos genéricos no.

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

muestra

0
indefinido

Intrínsecamente, el intérprete de FF Gecko también distingue entre Arrays y Objetos genéricos con distintas diferencias al evaluar las construcciones del lenguaje.

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);

exhibiendo

uno dos tres

[objeto Objeto]

["uno dos tres"]

4 .toSource () me olvidó! 

3 y mi longitud! 

({0: "uno", 1: "dos", 2: "tres", a: 4})

y 0 1 2 ay 0 1 2 a.

En cuanto a la afirmación de que todos los objetos son funciones:

No es ni sintácticamente ni semánticamente correcta de utilizar una instancia de objeto arbitrario como una función como 123()o "abc"()o []()o {}()o obj()donde objes cualquier tipo distinto Function, por lo que una instancia de objeto arbitrario no es una Function. Sin embargo, dado un objeto objy su tipo como Array, Boolean, Date, ..., ¿cómo objllegó a ser como un Array, Boolean, Date, ...? ¿Qué es un Array, Boolean, Date, ...?

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

muestra

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]
}

En todos los casos, sin equívocos, el tipo de objeto se manifiesta como una functiondefinición, de ahí la afirmación de que todos los objetos son funciones. (La ironía es que oscurecí y desdibujé intencionalmente la distinción de una instancia de objeto con la de su tipo. Aún así, esto muestra que "no se puede tener uno sin el otro", ¡Objeto y función! Las mayúsculas enfatizan el tipo como opuesto a la instancia.)

Tanto el paradigma funcional como el de objeto parecen ser fundamentales para la programación e implementación de las primitivas incorporadas de bajo nivel del intérprete JS, como Mathy JSONy true.

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

muestra

[object Math]

[object JSON]

(new Boolean(true))

En el momento del desarrollo de Javascript, estaba en boga un estilo de programación centrado en objetos (OOP, estilo de programación orientada a objetos, ¡el "es mi propio juego de palabras!) Y el intérprete fue bautizado de manera similar con Java para darle mayor credibilidad. . Las técnicas de programación funcional fueron relegadas a exámenes más abstractos y esotéricos que estudian las teorías de los Autómatas, Funciones Recursivas, Lenguajes Formales, etc. y como tales no son tan apetecibles. Sin embargo, las fortalezas de estas consideraciones formales se manifiestan claramente en Javascript, particularmente cuando se implementa en el motor Gecko de FF (es decir .toSource()).


La definición de Objeto para Función es particularmente satisfactoria porque se define como una relación de recurrencia. definido usando su propia definición!

function Function() { [native code] }
y dado que una función es un Objeto, el mismo sentimiento es válido
function Object() { [native code] }.

La mayoría de las otras definiciones se inactivan a un valor terminal estático. Sin embargo, eval()es una primitiva particularmente poderosa, por lo que un String también puede incorporar una funcionalidad arbitraria.

Tenga en cuenta de nuevo, la lengua vernácula utilizada anteriormente oscurece el tipo de objeto y la distinción de instancia.

Ekim
fuente
5

Todo en JavaScript es un objeto además de los tipos primitivos.

El código

var myArray = Array();

crea una instancia del objeto Array mientras

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

crea una instancia de objeto Object.

Prueba el siguiente código

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

Entonces verá que la diferencia está en el tipo de constructor de objeto.

La instancia del objeto Array contendrá todas las propiedades y métodos del prototipo Array.

Dasha Salo
fuente
2

La diferencia entre las matrices y los otros objetos en JavaScript. Si bien las matrices tienen una propiedad de longitud que se actualiza mágicamente, para objetos distintos de las matrices no hay forma de implementar dicha propiedad.

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

Las matrices se utilizan para almacenar cosas con un índice ordinal; úselas como una matriz, pila o cola tradicional. Un objeto es un hash; utilícelo para datos que tengan una clave distinta.

Parth Raval
fuente
2

Puede agregar propiedades con nombre a casi cualquier cosa en javascript, pero eso no significa que deba hacerlo. Arrayen javascript debe usarse como una lista, si desea usar una matriz asociativa en su Objectlugar.

Tenga en cuenta que si realmente desea usar una Arraypropiedad con nombre en lugar de Objectesas propiedades, no será accesible en un for...ofbucle y también puede obtener resultados inesperados cuando la codifica JSON para pasarla. Vea el ejemplo a continuación donde se ignoran todos los índices no numéricos :

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
fuente
-1

La {}-notación es simplemente azúcar sintáctica para hacer que el código sea más agradable ;-)

JavaScript tiene muchas construcciones similares como la construcción de funciones, donde function () es solo un sinónimo de

var Func = new Function("<params>", "<code>");
Darío
fuente
3
El constructor de funciones NO es un sinónimo de la función literal. El literal tiene un ámbito léxico mientras que el constructor es global. {}es una notación de objeto literal, []es una matriz literal, no estoy seguro de cuál es el punto de su respuesta.
Juan Mendes
Además, las funciones declaradas están disponibles antes de que se ejecute cualquier código, las asignaciones que utilizan el constructor de funciones no están disponibles hasta que se ejecuta el código que las crea.
RobG