L'auteur du matériel, dont nous publions la traduction aujourd'hui, dit que les objets JavaScript contiennent beaucoup de choses, dont vous ne pouvez même pas soupçonner l'existence, en les utilisant dans le travail quotidien. Les objets en JavaScript sont très faciles à créer, pratiques à utiliser, ils semblent compréhensibles et flexibles, et de nombreux programmeurs ne pensent tout simplement pas au fait que les objets ne sont pas si simples.

NB: Les informations tirées de la publication dans la pratique doivent être appliquées très soigneusement et sous la supervision de collègues plus expérimentés.
Ici, nous parlons de ce qui est caché dans les profondeurs des objets et discutons des subtilités de travailler avec eux.
Ayant maîtrisé ce matériel, vous connaîtrez les réponses aux questions suivantes:
- Comment rendre une propriété d'objet non supprimable?
- Quelles sont les propriétés avec des méthodes d'accès et quelles sont leurs fonctionnalités?
- Comment rendre une propriété immuable ou cachée?
- Pourquoi certaines propriétés ne sont-elles pas visibles dans les boucles
for-in
ou dans les résultats de la méthode Object.keys()
, et certaines sont visibles? - Comment «protéger» un objet contre toute modification?
- Comment comprendre un morceau de code similaire au suivant:
obj.id = 5; console.log(obj.id)
Types de propriétés d'objet
▍ Propriétés de stockage des données
Vous avez probablement créé d'innombrables objets ressemblant à ceci:
const obj = { name: 'Arfat', id: 5 } obj.name
Les propriétés de
name
et d'
id
de l'objet
obj
sont appelées propriétés de
obj
données ou «Propriétés de données». Ce sont des propriétés familières que l'on trouve constamment dans le code JavaScript. Quels autres types de propriétés les objets peuvent-ils avoir?
▍ Propriétés avec méthodes d'accès
Ces propriétés sont également connues sous le nom de getters et setters; elles se trouvent également dans d'autres langages de programmation comme C # ou Python. Une propriété avec la propriété Accessor est une combinaison de deux fonctions -
get
et
set
.
Lors de la déclaration de telles propriétés, au lieu d'utiliser la construction de type
:
traditionnelle, la syntaxe suivante est utilisée:
const accessorObj = { get name() { return 'Arfat'; } }; accessorObj.name;
Jetez un œil à l'objet
accesorObj
et comparez-le avec l'objet
dataObj
. Apparemment, ils montrent maintenant le même comportement. Pour décrire le premier objet, nous avons utilisé le mot-clé
get
, suivi de la déclaration de la fonction. Pour accéder à une propriété similaire, bien qu'elle soit représentée par une fonction, vous n'avez pas besoin de mettre des parenthèses après le nom de la propriété pour appeler cette fonction. Autrement dit, une conception comme
accessorObj.name();
incorrect.
Lorsque vous essayez d'accéder à la propriété
accessorObj.name
, c'est-à-dire lorsque vous essayez de la lire, la fonction correspondante est exécutée et la valeur qui lui est renvoyée devient la valeur de la propriété
name
.
Les fonctions
get
sont appelées getters; elles sont responsables de l'obtention des valeurs. Si nous continuons notre exemple et essayons de changer la valeur de la propriété
name
de l'objet
accessorObj
, disons, en exécutant la commande
accessorObj.name = 'New Person';
, il s'avère que rien ne se passera. Le point ici est que la fonction setter n'est pas associée à la clé de
name
. Ces fonctions vous permettent de personnaliser l'ordre d'attribution de nouvelles valeurs aux propriétés des objets, dont l'accès est organisé à l'aide de getters.
Voici à quoi ressemble une déclaration d'objet avec un getter et un setter:
const accessorObj = { _name: 'Arfat', get name() { return this._name; }, set name(value) { this._name = value; } };
La fonction setter reçoit ce qu'elle essaie d'affecter à la propriété de l'objet en tant que paramètre. Vous pouvez maintenant enregistrer quelque chose dans la propriété de l'objet. Dans ce cas, nous créons une propriété «privée» de l'objet
_name
. Le premier caractère du nom d'une telle propriété est un trait de soulignement, qui n'est rien d'autre qu'un indice pour le programmeur, indiquant que cette propriété est destinée aux besoins internes de l'objet. De plus, nous travaillons avec lui lors de l'accès à la propriété de l'objet
name
, dont l'accès est réglementé par le getter et le setter.
Dans le même temps, dans la fonction getter, avant de renvoyer la valeur de la propriété
_name
, nous pouvons la modifier.
Voici à quoi cela pourrait ressembler:
const obj = { get name() { return this._name.toUpperCase(); }, set name(value) { this._name = value; }, get id() { return this._id.toString(2);
Ce programme, soit dit en passant, contient la réponse à l'une des questions posées au début de l'article, qui concerne l'analyse du code incompréhensible à première vue.
Pourquoi quelqu'un aurait-il besoin de propriétés avec des méthodes d'accès si vous pouvez travailler en toute sécurité avec des propriétés ordinaires? Par exemple, ils peuvent être nécessaires pour consigner des informations sur les lectures de propriété ou pour stocker un historique des modifications des valeurs de propriété. Les propriétés avec des méthodes d'accès nous donnent toutes les possibilités de traitement des données à l'aide de fonctions et la simplicité caractéristique de travailler avec des propriétés ordinaires. En savoir plus sur l'utilisation de ces propriétés
ici .
Comment JavaScript distingue-t-il les propriétés ordinaires qui stockent les données des propriétés avec des méthodes d'accès? Découvrez ça.
Descripteurs de propriétés d'objet
À première vue, il peut sembler qu'il existe une correspondance directe entre les clés et les valeurs stockées dans les objets. Cependant, ce n'est pas entièrement vrai.
▍ Attributs de propriété
Chaque clé de l'objet est associée à un ensemble d'attributs qui déterminent les caractéristiques de la valeur associée à cette clé. Ces attributs peuvent également être considérés comme des métadonnées décrivant une paire
:
.
Les attributs sont utilisés pour définir et décrire l'état des propriétés des objets. L'ensemble des attributs de propriété est appelé un descripteur. Il existe six attributs de propriété:
[[Value]]
[[Get]]
[[Set]]
[[Writable]]
[[Enumerable]]
[[Configurable]]
Pourquoi les noms d'attribut de propriété dans cette liste sont-ils inclus dans la construction
[[]]
? Les doubles crochets indiquent qu'il s'agit d'entités utilisées par les mécanismes internes du langage. Un programmeur JS ne peut pas accéder directement à ces propriétés. Afin de les influencer, des méthodes appropriées sont utilisées.
Considérez l'image suivante, prise à
partir d'ici , sur laquelle vous pouvez voir l'objet et les attributs de ses propriétés.
Objet et attributs de ses propriétésNotre objet a 2 clés -
x
et
y
. De plus, un ensemble d'attributs est associé à chacun d'eux.
Comment, en utilisant JavaScript, obtenir des informations sur l'objet, similaires à celles présentées dans la figure précédente? Vous pouvez utiliser la fonction
Object.getOwnPropertyDescriptor()
pour cela. Il prend un objet et le nom de sa propriété, puis renvoie un objet contenant les attributs de cette propriété. Voici un exemple:
const object = { x: 5, y: 6 }; Object.getOwnPropertyDescriptor(object, 'x');
Il convient de noter que la composition des attributs d'une propriété particulière dépend de son type. Les six attributs de la même propriété sont introuvables.
- Si nous parlons de propriétés avec des données, elles n'auront alors que les attributs
[[Value]]
, [[Writable]]
, [[Enumerable]]
et [[Configurable]]
. - Les propriétés avec des méthodes d'accès, au lieu des attributs
[[Value]]
et [[Writable]]
, ont les attributs [[Get]]
et [[Set]]
.
▍ [[Valeur]]
Cet attribut stocke ce qui est retourné lorsque vous essayez d'obtenir la valeur de propriété d'un objet. Autrement dit, si dans l'exemple précédent nous utilisons une construction du formulaire
object.x
, nous obtenons ce qui est stocké dans l'attribut
[[Value]]
. La même chose se produit lorsque vous essayez de lire les propriétés d'un objet à l'aide de crochets.
▍ [[Obtenir]]
Cet attribut stocke une référence à une fonction, qui est une propriété getter. Cette fonction est appelée sans arguments lors de la tentative de lecture de la valeur d'une propriété.
▍ [[Définir]]
C'est là que le lien vers la fonction déclarée lors de la création de la propriété setter est stocké. Il est appelé avec un argument représentant la valeur qu'ils ont essayé d'affecter à la propriété, c'est-à-dire qu'il est appelé lors de chaque opération d'affectation d'une propriété à une nouvelle valeur.
const obj = { set x(val) { console.log(val)
Dans cet exemple, le côté droit de l'expression est transmis en tant qu'argument
val
à la fonction setter.
Voici le code qui montre l'utilisation des setters et des getters.
▍ [[Inscriptible]]
Cet attribut contient une valeur booléenne. Il indique si la valeur de la propriété peut être remplacée ou non. Si
false
est stocké ici, les tentatives de modification de la valeur de la propriété échoueront.
▍ [[énumérable]]
Une valeur logique est également stockée ici. Cet attribut contrôle l'émission de la propriété
for-in
boucles
for-in
. S'il est défini sur
true
, il sera possible de travailler avec la propriété à l'aide de ces cycles.
▍ [[Configurable]]
Cet attribut est également représenté par une valeur booléenne. C'est ce qui se passe si
false
est stocké:
- La propriété ne peut pas être supprimée.
- Vous ne pouvez pas convertir des propriétés qui stockent des données en propriétés avec des méthodes d'accès et vice versa. Les tentatives pour effectuer de telles transformations ne mèneront à rien.
- Il ne sera pas autorisé de modifier les valeurs d'attribut de propriété. Autrement dit, les valeurs actuelles des attributs
[[Enumerable]]
, [[Configurable]]
, [[Get]]
et [[Set]]
seront inchangées.
L'effet de la définition de cet attribut sur
false
dépend également du type de propriété. Cet attribut, en plus des effets ci-dessus sur les propriétés, agit sur eux et ainsi:
- S'il s'agit d'une propriété qui stocke des données, l'attribut
[[Writable]]
ne peut être changé que de true
à false
. - Jusqu'à ce que l'attribut
[[Writable]]
soit défini sur false
, l'attribut [[Value]]
peut être modifié. Mais une fois que les attributs [[Writable]]
et [[Configurable]]
sont définis sur false
, la propriété se révèle être inscriptible, non supprimable et immuable.
Travailler avec des descripteurs
Maintenant que nous nous sommes familiarisés avec les attributs, nous nous demanderons comment nous pouvons les influencer. JavaScript a des fonctions spéciales pour travailler avec des descripteurs de propriétés. Parlons-en.
▍ Méthode Object.getOwnPropertyDescriptor ()
Nous avons déjà rencontré cette méthode. Il, en prenant un objet et le nom de sa propriété, renvoie soit
undefined
, soit un objet avec un descripteur de propriété.
▍ Méthode Object.defineProperty ()
Il s'agit d'une méthode d'
Object
statique qui vous permet d'ajouter des propriétés à des objets ou de modifier des propriétés existantes. Il prend trois arguments - un objet, un nom de propriété et un objet avec un descripteur. Cette méthode renvoie un objet modifié. Prenons un exemple:
const obj = {};
Il peut être exécuté dans Node.js. Le code s'est avéré assez volumineux, mais en fait, c'est assez simple. Nous allons l'analyser en nous concentrant sur les commentaires du formulaire
// #n
.
Dans le fragment
#1
nous utilisons la fonction
defineProperty
, en lui passant l'objet
obj
, le nom de la propriété
id
et un objet descripteur qui contient uniquement la propriété
value
, indiquant que
42
sera écrit dans l'attribut
[[Value]]
. N'oubliez pas que si vous ne transmettez pas de valeurs pour des attributs tels que
[[Enumerable]]
ou
[[Configurable]]
dans cet objet, ils seront définis sur
false
par défaut. Dans ce cas, les attributs
[[Writable]]
,
[[Enumerable]]
et
[[Configurable]]
propriété
id
sont définis sur
false
.
À l'endroit marqué
#2
, nous essayons d'afficher une représentation sous forme de chaîne de l'objet dans la console. Étant donné que sa propriété
id
n'est pas énumérable, elle ne sera pas affichée. De plus, la propriété existe, ce qui prouve sa conclusion réussie par la commande
#3
.
En créant un objet (fragment
#4
), nous définissons une liste complète d'attributs. En particulier, définissez
[[Writable]]
sur
false
.
Avec les commandes
#5
et
#7
nous affichons la valeur de la propriété
name
. Mais entre eux (fragment
#6
), nous avons essayé de changer cette valeur. Cette opération n'a pas modifié la valeur de la propriété car son attribut
[[Writable]]
est défini sur
false
. Par conséquent, les deux commandes génèrent la même chose sur la console.
La commande
#8
est une tentative de suppression de la propriété
id
. Rappelez-vous que son attribut
[[Configurable]]
est défini sur
false
, ce qui signifie qu'il ne peut pas être supprimé. Cela est prouvé par l'équipe
#9
.
Le fragment
#10
montre l'utilisation de la fonction
Object.defineProperties () . Elle fonctionne de la même manière que la fonction
defineProperty()
, mais elle permet, en un seul appel, d'affecter plusieurs propriétés de l'objet, tandis que
defineProperty()
fonctionne avec une seule propriété de l'objet.
Protection des objets
De temps en temps, le développeur doit protéger les objets des interférences extérieures. Par exemple, étant donné la flexibilité de JavaScript, il est très facile de modifier par erreur les propriétés d'un objet qui ne devrait pas changer. Il existe trois façons principales de protéger les objets.
▍ Méthode Object.preventExtensions ()
La méthode
Object.preventExtensions()
empêche l'objet de se développer, c'est-à-dire d'y ajouter de nouvelles propriétés. Il prend un objet et le rend non extensible. Notez que vous pouvez supprimer des propriétés d'un tel objet. Prenons un exemple:
const obj = { id: 42 }; Object.preventExtensions(obj); obj.name = 'Arfat'; console.log(obj);
Pour savoir si un objet n'est pas extensible, vous pouvez utiliser la méthode
Object.isExtensible()
. S'il renvoie
true
, vous pouvez ajouter de nouvelles propriétés à l'objet.
▍ Méthode Object.seal ()
La méthode
seal()
semble «sceller» les objets. Voici de quoi nous parlons:
- Son utilisation empêche l'ajout de nouvelles propriétés à l'objet (en cela, il est similaire à
Object.preventExtensions()
). - Il rend toutes les propriétés existantes d'un objet non configurables.
- Les valeurs des propriétés existantes, si leur attribut
[[Writable]]
n'est pas défini sur false
, peuvent être modifiées.
En conséquence, il s'avère que cette méthode empêche l'ajout de nouvelles propriétés à l'objet et la suppression des propriétés qui y existent.
Prenons un exemple:
const obj = { id: 42 }; Object.seal(obj); delete obj.id
Pour vérifier si l'objet est "scellé" ou non, vous pouvez utiliser la méthode
Object.isSealed()
.
▍ Méthode Object.freeze ()
La méthode
freeze()
vous permet de «figer» des objets, en les dotant du niveau de protection le plus élevé possible en JavaScript. Voici comment cela fonctionne:
Object.seal()
un objet en utilisant Object.seal()
.- Interdit complètement la modification des propriétés existantes de l'objet.
- Interdit de modifier les descripteurs de propriété.
Voici un exemple:
const obj = { id: 42 }; Object.freeze(obj); delete obj.id
Vous pouvez vérifier l'objet s'il est «gelé» à l'aide de la méthode
Object.isFrozen()
.
▍ Aperçu des méthodes utilisées pour protéger les objets
Il est important de noter que les méthodes ci-dessus utilisées pour protéger les objets affectent uniquement leurs propriétés qui ne sont pas des objets.
Voici un tableau récapitulatif des méthodes envisagées de protection des objets, qui est extrait
d'ici .
| Création de propriété
| Lecture de propriété
| Écrasement de propriété
| Enlèvement de propriété
|
Object.freeze()
| - | +
| - | - |
Object.seal()
| - | +
| +
| - |
Object.preventExtensions()
| - | +
| +
| +
|
Résumé
Étant donné la fréquence d'utilisation des objets en JavaScript, il est important que chaque développeur sache comment ils sont organisés. Nous espérons que ce que vous avez appris en lisant ce document vous sera utile. De plus, vous connaissez maintenant les réponses aux questions énumérées au début de l'article.
Chers lecteurs! Comment protégez-vous les objets JavaScript?