Pourquoi puis-je ajouter des propriétés nommées à un tableau comme s'il s'agissait d'un objet?

105

Les deux extraits de code différents suivants me semblent équivalents:

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

et

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

parce qu'ils se comportent tous les deux de la même manière, et aussi typeof(myArray) == typeof(myObjects)(tous deux donnent «objet»).

Y a-t-il une différence entre ces variantes?

Prinzdezibel
la source

Réponses:

131

Pratiquement tout en javascript est un objet, vous pouvez donc "abuser" d'un objet Array en définissant des propriétés arbitraires dessus. Cela devrait cependant être considéré comme nocif . Les tableaux sont destinés aux données indexées numériquement - pour les clés non numériques, utilisez un objet.

Voici un exemple plus concret de la raison pour laquelle les touches non numériques ne «correspondent» pas à un tableau:

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

alert(myArray.length);

Cela n'affichera pas «2», mais «0» - effectivement, aucun élément n'a été ajouté au tableau, juste quelques nouvelles propriétés ajoutées à l'objet tableau.

Paul Dixon
la source
4
myArray.length renvoie un index / clé numérique du dernier élément du tableau mais pas le nombre réel d'éléments. Les propriétés de l'objet Array sont-elles différentes des valeurs de tableau?
Dasha Salo
1
J'essayais juste d'illustrer la sémantique voulue pour que l'objet Array soit abusé si vous le traitez simplement comme un objet normal. L'article lié fait un meilleur travail cependant :)
Paul Dixon
13
La prochaine fois que quelqu'un dira que JavaScript est un bon langage pour développer, je lui montrerai cet exemple. Je vous remercie.
Olivier Pons
@Olivier, ce que vous appelez un "bug" peut aussi être une "fonctionnalité" géniale. Vous pouvez ajouter une Tittle et la description des réseaux sans affecter leur contenu ou la longueur et sans avoir à les envelopper dans des objets avec title, descriptionet itemspropriétés. Tout dépend de votre connaissance de la langue et de la manière dont vous l'utilisez.
tao
L'utilisation de propriétés personnalisées sur des tableaux n'est pas intrinsèquement erronée. Le problème, c'est de s'attendre à ce qu'ils agissent en tant que membres du groupe une fois que vous le faites. Ce sont des propriétés de tableau, pas des membres, donc non affectés par les méthodes de tableau. C'est en fait dit par l'auteur de l'article lié ci-dessus, dans les commentaires. Maintenant, en toute honnêteté, je le déconseillerais en tant que pratique, car cela déroutera probablement les gens qui utilisent votre code. Ou, s'ils ne font que commencer, cela les mettra sur une voie dangereuse, par le pouvoir de l'exemple. Mais je ne dirais pas que JavaScript est mauvais car il permet à la plupart des choses que la plupart ne s'attendent pas à être autorisées.
tao
14

Dans les tableaux JS se trouvent des objets, juste légèrement modifiés (avec quelques fonctions supplémentaires).

Fonctions comme:

concat
every   
filer
forEach
join
indexOf
lastIndexOf
map
pop
push
reverse
shift
slice
some
sort
splice
toSource
toString
unshift
valueOf 
Casey
la source
Bien que je ne pense pas que toutes les fonctions répertoriées soient intégrées à chaque implémentation JS, vous avez compris. L'autre différence serait un prototype différent (ce qui est impliqué par ces fonctions supplémentaires).
Rashack
6

Je pense, moi trop métaphorique et cryptique avec la réponse précédente. Une clarification suit.

Une instance de Array, Boolean, Date, Function, Number, RegExp, String est un objet mais amélioré avec des méthodes et des propriétés spécifiques à chaque type. Par exemple, un tableau a une lengthpropriété prédéfinie alors que les objets génériques n'en ont pas.

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

affiche

0
indéfini

Intrinsèquement, l'interpréteur FF Gecko fait également la distinction entre les tableaux et les objets génériques avec des différences distinctes évaluant les constructions de langage.

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

affichage

un deux trois

[objet Objet]

["un deux trois"]

4 .toSource () m'a oublié! 

3 et ma longueur! 

({0: "un", 1: "deux", 2: "trois", a: 4})

et 0 1 2 aet 0 1 2 a.

Concernant l'affirmation selon laquelle tous les objets sont des fonctions:

Il n'est ni syntaxiquement ni sémantiquement correct d'utiliser une instance d'objet arbitraire comme une fonction comme 123()ou "abc"()ou []()ou {}()ou obj()objest un type autre que Function, donc un objet arbitraire INSTANCE n'est pas a Function. Cependant, étant donné un objet objet son type comme Array, Boolean, Date, ..., comment est-il objarrivé à être en tant que Array, Boolean, Date, ...? Qu'est-ce qu'un Array, Boolean, Date, ...?

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

affiche

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

Dans tous les cas, sans équivoque, le type d'objet se manifeste comme une functiondéfinition, d'où l'affirmation que tous les objets sont des fonctions! (La ironie est que j'ai intentionnellement obscurci et brouillé la distinction d'une instance d'objet avec celle de son type! Pourtant, cela montre "vous ne pouvez pas avoir l'un sans l'autre", Objet et fonction! La capitalisation met l'accent sur le type comme opposé à l'instance.)

Un paradigme fonctionnel et un paradigme d'objet semblent être fondamentaux pour la programmation et la mise en œuvre des primitives intégrées de bas niveau de l'interpréteur JS, telles que Mathet JSONet true.

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

affiche

[object Math]

[object JSON]

(new Boolean(true))

Au moment du développement de Javascript, un style de programmation orienté objet (POO - Object Oriented Programming style - le "s" est mon propre jeu de mots!) Était en vogue et l'interpréteur a été baptisé de la même manière avec Java pour lui donner une plus grande crédibilité . Les techniques de programmation fonctionnelle ont été reléguées à des examens plus abstraits et ésotériques étudiant les théories des automates, des fonctions récursives, des langages formels, etc. et, en tant que telles, ne sont pas acceptables. Cependant, les points forts de ces considérations formelles sont clairement manifestes dans Javascript, en particulier tel qu'implémenté dans le moteur Gecko de FF (ie. .toSource()).


La définition d'objet pour Function est particulièrement satisfaisante car elle est définie comme une relation de récurrence! défini en utilisant sa propre définition!

function Function() { [native code] }
et comme une fonction est un objet, le même sentiment vaut
function Object() { [native code] }.

La plupart des autres définitions sont suspendues à une valeur terminale statique. Cependant, eval()est une primitive particulièrement puissante et donc une chaîne peut également intégrer des fonctionnalités arbitraires.

Notez encore une fois, le vernaculaire utilisé ci-dessus obscurcit le type d'objet et la distinction d'instance.

Ekim
la source
5

Tout en JavaScript est un objet en plus des types primitifs.

Le code

var myArray = Array();

crée une instance de l'objet Array pendant que

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

crée une instance de l'objet Object.

Essayez le code suivant

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

Vous verrez donc que la différence réside dans le type de constructeur d'objet.

L'instance de l'objet Array contiendra toutes les propriétés et méthodes du prototype Array.

Dasha Salo
la source
2

La différence entre les tableaux et les autres objets en JavaScript. Alors que les tableaux ont une propriété de longueur mise à jour comme par magie, pour les objets autres que les tableaux, il n'y a aucun moyen d'implémenter une telle propriété.

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

Les tableaux sont utilisés pour stocker des éléments avec un index ordinal - utilisez-le comme un tableau, une pile ou une file d'attente traditionnel. Un objet est un hachage - utilisez-le pour les données qui ont une clé distincte.

Parth Raval
la source
2

Vous pouvez ajouter des propriétés nommées à presque tout en javascript, mais cela ne signifie pas que vous devriez le faire. Arrayen javascript doit être utilisé comme une liste, si vous souhaitez utiliser un tableau associatif à la Objectplace.

Sachez que si vous voulez vraiment utiliser un Arrayavec des propriétés nommées au lieu de Objectces propriétés ne sera pas accessible dans une for...ofboucle et que vous pourriez également obtenir des résultats inattendus lorsque JSON l'encodage pour le transmettre. Voir l'exemple ci-dessous où tous les index non numériques sont ignorés:

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
la source
-1

La {}-notation n'est que du sucre syntaxique pour rendre le code plus agréable ;-)

JavaScript a de nombreuses constructions similaires comme la construction de fonctions, où function () n'est qu'un synonyme de

var Func = new Function("<params>", "<code>");
Dario
la source
3
Le constructeur de fonction n'est PAS un synonyme du littéral de fonction. Le littéral a une portée lexicale tandis que le constructeur est global. {}est la notation d'objet littérale, []est un tableau littéral, je ne sais pas quel est le point de votre réponse.
Juan Mendes
De plus, les fonctions déclarées sont disponibles avant l'exécution de tout code, les affectations utilisant le constructeur Function ne sont pas disponibles tant que le code qui les crée ne s'exécute pas.
RobG