Le 23 décembre 2013
Pour la plupart, en JavaScript, ce que vous voyez est ce que vous obtenez. Une valeur est une valeur ; il n’y a pas d’astuces. Parfois cependant, vous voulez une valeur qui est basée sur certaines autres valeurs : le nom complet de quelqu’un, par exemple, est une concaténation de son prénom et de son nom. Si vous avez un objet person
, et que vous voulez que les utilisateurs de cet objet puissent définir le nom complet, le prénom ou le nom de famille, et voir ce changement immédiatement reflété dans les autres valeurs, vous le construiriez conventionnellement avec des fonctions :
person.setLastName('Smith');person.setFirstName('Jimmy');person.getFullName(); // Jimmy Smith
Mais c’est laid, et nécessite que les utilisateurs de votre objet se soucient que les propriétés soient liées ; dans un exemple plus complexe, cela pourrait ne pas être aussi évident qu’avec les noms. Heureusement, il y a une meilleure façon, ajoutée dans ECMAScript 5.
Meet getters and setters.
How
Faisons cet objet personne. Nous voulons être en mesure de définir le prénom, le nom de famille ou le nom complet, et qu’il mette à jour les deux autres automatiquement.
var person = { firstName: 'Jimmy', lastName: 'Smith', get fullName() { return this.firstName + ' ' + this.lastName; }, set fullName (name) { var words = name.toString().split(' '); this.firstName = words || ''; this.lastName = words || ''; }}person.fullName = 'Jack Franklin';console.log(person.firstName); // Jackconsole.log(person.lastName) // Franklin
Alors, que se passe-t-il ici ?
Les mots-clés get et set sont importants. Ils sont suivis de la propriété à laquelle ils se rapportent (fullName
) et d’un corps de fonction qui définit le comportement lorsque la propriété est accédée (name = person.fullName
) ou modifiée (person.fullName = 'Some Name'
).
Ces deux mots-clés définissent des fonctions accesseurs : un getter et un setter pour la propriété fullName
. Lorsque la propriété est accédée, la valeur de retour du getter est utilisée. Lorsqu’une valeur est définie, le setter est appelé et on lui passe la valeur qui a été définie. C’est à vous de faire ce que vous faites avec cette valeur, mais ce qui est retourné par le setter est la valeur qui a été passée – donc vous n’avez pas besoin de retourner quoi que ce soit.
La façon officielle : Object.defineProperty
A côté de la méthode en ligne de déclaration des getters et setters, on peut aussi le faire plus explicitement via Object.defineProperty
(MDN Documentation). Cette méthode prend trois arguments. Le premier est l’objet auquel ajouter la propriété, le deuxième est le nom de la propriété et le troisième est un objet qui décrit la propriété (appelé descripteur de la propriété). Voici un exemple qui reproduit l’exemple ci-dessus :
var person = { firstName: 'Jimmy', lastName: 'Smith'};Object.defineProperty(person, 'fullName', {get: function() {return firstName + ' ' + lastName;},set: function(name) {var words = name.split(' ');this.firstName = words || '';this.lastName = words || '';}});
L’avantage ici n’est pas immédiatement apparent. Mis à part le fait de pouvoir ajouter des propriétés après la création de l’objet initial, y a-t-il un réel avantage ?
Lorsque vous définissez une propriété de cette façon, vous pouvez faire beaucoup plus que simplement définir un setter ou un getter. Vous pouvez également passer les clés suivantes :
-
configurable
(false
par défaut) : si c’est vrai, la configuration de la propriété sera modifiable à l’avenir. -
enumerable
(false
par défaut) : si c’est vrai, la propriété apparaîtra lors du bouclage de l’objet (for (var key in obj)
).
Nous pouvons également définir des propriétés qui n’ont pas de getters ou setters explicites :
Object.defineProperty(person, 'age', { value: 42});
Ceci créera person.age
, et lui donnera la valeur 42. Il est important de noter que cette propriété n’est pas inscriptible. L’appel à person.age = 99
n’aura aucun effet. De cette façon, vous pouvez créer des propriétés en lecture seule. Si une propriété a une clé value
définie, elle ne peut pas avoir de getter ou de setter. Les propriétés peuvent avoir des valeurs ou des accesseurs, pas les deux.
Non seulement cela, mais parce que la propriété enumerable
a par défaut la valeur false
, cette propriété n’apparaîtra pas lorsque nous bouclons sur les clés de l’objet.
Si nous voulions rendre une propriété inscriptible, nous aurions besoin de définir la propriété writable
:
Object.defineProperty(person, 'age', { value: 42, writable: true});
Maintenant, person.age = 99;
aura l’effet désiré.
Surutilisation
Rappellez-vous : juste parce qu’une fonctionnalité existe, elle n’a pas besoin d’être utilisée tout le temps. Les Getters et Setters ont leurs cas d’utilisation, mais n’en abusez pas, ou vous vous retrouverez très probablement avec un design déroutant pour ceux qui interagissent avec vos objets. Utilisés avec précaution, ils sont très puissants. Mais avec un grand pouvoir vient une grande responsabilité.
Support des navigateurs ?
IE9 et plus ont un support complet pour Object.defineProperty
, ainsi que Safari 5+, Firefox 4+, Chrome 5+ et Opera 12+. Si vous travaillez avec Node.js, il y a un support complet. N’aimez-vous pas Node ?!
Cet article a été co-écrit avec Tom Ashworth. Merci à Tom pour toute son aide à mettre cela ensemble.
Si vous avez apprécié cet article, rejoignez la newsletter pour recevoir des mises à jour sur le nouveau contenu 😎.
Tous les articles de blog
Si vous avez apprécié cet article, assurez-vous de me suivre sur Twitter.