Passer par Valeur vs Passer par Référence en JavaScript

Si vous débutez en JavaScript, il y a de fortes chances que vous ayez déjà rencontré certains des comportements amusants que ce langage a à offrir (pièce A). Au début, ces bizarreries étranges peuvent sembler ridicules et frustrantes, mais je promets qu’il y a une méthode derrière toute cette folie.

L’un des obstacles les plus difficiles à surmonter, à mon humble avis, est la différence entre le passage par valeur et le passage par référence. Pourquoi ce concept est-il si délicat? Pour commencer, vous pouvez certainement aller assez loin sans vraiment comprendre comment JavaScript interagit avec les valeurs primitives et les valeurs de référence. Cela peut, et le plus souvent, entraîner une tonne de bugs difficiles à détecter et ennuyeux à corriger. Deuxièmement, c’est un concept qui APPARAÎTRA dans les entretiens techniques, donc ne pas le comprendre comptera comme un énorme drapeau rouge contre vous.

N’ayez crainte, camarade lecteur! Que l’éducation commence

Types de données primitifs

En JavaScript, nous pouvons diviser les types de données en deux compartiments différents, les types de données primitifs et les objets.

Graphique illustrant les types de données primitifs, ou valeurs, et les types d’objets, ou valeurs de référence

Il existe six types de données primitifs en JavaScript: string, number, boolean, undefined, null, et symbol à partir de l’ES6.

Les types de données primitifs sont transmis ou copiés par valeur et sont immuables, ce qui signifie que la valeur existante ne peut pas être modifiée comme un tableau ou un objet le peut. Jetons un coup d’œil au code ci-dessous pour voir cela en action.

Créé en utilisant jsbin.com

Ici, nous avons créé deux variables, x = 10 et y = x. Puisque 10 est un nombre et une valeur primitive, lorsque nous définissons y = x, nous copions en fait la valeur, c’est-à-dire 10, et l’affectons à y. Nous pouvons également visualiser cela en utilisant le tableau ci-dessous.

Si nous devions changer la valeur de x, nous verrions que y conserve sa valeur de 10. Encore une fois, c’est parce que les valeurs primitives sont copiées, donc la valeur de y est indépendante de la valeur de x. Pensez-y comme faire une photocopie d’une image. Après avoir fait la copie, vous avez deux images identiques: un original et un fac-similé. Si vous deviez couper l’original en deux, seul l’original serait modifié et le fac-similé resterait exactement le même.

Nous écrasons la valeur de x mais y reste le même

Objets de référence

Les objets, en revanche, sont passés par référence et pointent vers un emplacement en mémoire pour la valeur, pas la valeur elle-même. Jetons un coup d’œil à cela dans notre code.

Les variables x et y pointent désormais vers des objets plutôt que vers des types de données primitifs

Dans cet exemple, x est maintenant un objet pointant vers {dog: "poodle"}. Lorsque nous créons la variable y et lui attribuons la valeur de x, nous pouvons maintenant exploiter les différentes propriétés de x qui inclut la valeur de dog, c’est-à-dire "poodle". Cela semble être exactement la même logique utilisée pour les valeurs primitives, mais jetons un coup d’œil à notre tableau pratique ci-dessous pour voir la différence subtile, mais importante.

X et y pointent tous deux vers une adresse (composée) en mémoire qui stocke une référence à l’objet

Maintenant, ce graphique semble un peu différent de celui où nos variables x et y détenaient des types de données primitifs. Dans cette version, nous voyons que les valeurs pour x et y ne sont pas des types de données mais des références à une adresse en mémoire, la même adresse en fait! Voyons maintenant ce qui arrive à x si nous ajoutons une nouvelle propriété de size à y

x renvoie toujours un objet mais maintenant il a également une propriété supplémentaire de size ! Encore une fois, cela est dû au fait que x et y pointent tous les deux vers le même objet de référence, de sorte que toute modification apportée à une variable sera visible dans l’autre.

Le graphique illustre comment un changement de y met à jour la valeur de référence partagée avec x

Pour m’aider à me souvenir de ce concept, j’aime penser aux valeurs de référence comme une maison et aux variables comme des personnes qui vivent dans cette maison. Tous les résidents (variables) peuvent dire « J’ai une maison » et pointer vers la même maison. Si un seul résident décide de peindre la maison en jaune, tous les résidents ont maintenant une maison jaune car elle est partagée.

Jetons un coup d’œil à un autre exemple contenant une variété d’objets de référence.

Dans ce code, nous commençons par une variable person qui contient des propriétés de name, age et hobbies. Lorsque nous imprimons cet objet sur la console, nous obtenons exactement ce que nous attendons — le même objet que nous venons de créer.

Ensuite, nous avons une fonction appelée changePerson qui prend un argument, apporte quelques modifications, puis renvoie un objet. Lorsque nous créons la variable thirdPerson, nous appelons la fonction changePerson en y passant notre objet d’origine person. Le bit intéressant est ce qui se passe lorsque nous imprimons à nouveau sur la console thirdPerson et person.

Notez que console.log(thirdPerson) renvoie un tout nouvel objet avec de nouvelles propriétés. Regardez maintenant ce que console.log(person) renvoie. Ceci est similaire à notre objet d’origine, mais il contient de nouvelles valeurs de propriété qui ont été introduites dans notre fonction changePerson.

Vérification de l’égalité

Enfin, examinons comment les types de données primitifs et les objets de référence se comportent avec les opérateurs d’égalité.

En ce qui concerne les types de données primitifs, peu importe ce qui se trouve à droite du signe = tant que les valeurs sont les mêmes. Nous pouvons le voir ci-dessus avec les variables a et b qui sont écrites différemment mais évaluent à la même valeur lorsque nous utilisons le ===, l’opérateur d’égalité stricte.

L’inverse est vrai dans le deuxième exemple pour dog et cat. Bien qu’il puisse sembler qu’ils contiennent des valeurs identiques, est un tableau et un objet de référence, ce qui signifie que === vérifie si dog et cat ont la même référence à la valeur en mémoire. D’autre part, bird === dog est vrai car ils partagent le même objet de référence.

le chien et l’oiseau partagent la même référence alors que le chat ne le fait pas malgré un tableau identique

Conclusion

Et cela conclut notre introduction dans pass by value vs pass by reference. Il y a d’autres sujets qui peuvent être couverts sous ce parapluie fondamental, y compris ce qui se passe lorsqu’une référence est écrasée ou perdue, comment copier une référence pour créer un nouvel objet ET s’assurer que la copie est une copie profonde, pour n’en nommer que quelques-uns. Je vous recommande de consulter les ressources que j’ai utilisées ci-dessous, qui abordent plus en détail certains de ces sujets supplémentaires.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.