Comment cloner des objets en Javascript ?
Aujourd'hui le BlogDuWebdesign vous propose de vous pencher sur un point precis du developpement Javascript : le clonage d'objets
Le fond du probleme
Les plus jeunes développeurs parmi vous se demandent peut-être en quoi quelque chose d'aussi simple que copier un objet en Javascript mérite un article complet. Bande de naïfs ! Copier un objet est loin d'être une action triviale, et peut vous mener vers des bugs particulièrement complexes à débusquer.
Pour illustrer mon propos, jetez donc un oeil au code suivant (à partir de la ligne 31), puis au résultat. Est-ce réellement ce que vous attendiez ?
See the Pen GEyJrd by Benjamin SANCHEZ (@B_Sanchez) on CodePen.
Comme vous pouvez le voir, modifier le clone modifie aussi l'original ! Cela vient du fait qu'en Javascript, une assignation comme celle-là colonne effectivement les valeurs du type primitifs (string, numbers, …), mais pas les objets. Pour ces derniers, au lieu de faire une copie le code fait une référence. Finalement, les deux variables contiennent le "même" objet.
Qu'est-ce qu'une "Shallow" copy ?
Si vous remontez voir tous les exemples de méthodes que j'ai fournis dans le codepen, vous pourrez voir une méthode nomme object _asign. Cette méthode assigne toutes les propriétés de l'objet de droite sur l'objet de gauche, puis renvoie ce dernier. En faisant cela avec un objet tout neuf à gauche, nous pouvons effectivement "cloner" notre objet, en ayant un objet qui possède toutes les propriétés de notre original. Essayez !
Maintenant que vous avez essayé, vous pouvez remarquer que tout n'est pas aussi rose que prévu : la propriété "objet" de notre original n'a pas été clonée, mais juste passée en référence. C'est ce que l'on appelle un "shallow" clone (ou clone peu profond) et qu'il faut bien différencier du "deep clone", qui clone un objet dans toute sa profondeur.
Des méthodes de clonage profond
Vous pourrez retrouver deux autres méthodes dans le codepen : boucle avec recursion et json. Ces deux méthodes permettent de faire du clonage profond !
La première fonctionne en bouclant sur un objet et en examinant le type de chacune des propriétés. Toutes les primitives sont copiées par assignation, tous les objets son clone en rappelant boucle avec récursion elle-même (ce qu'on appelle une récursion donc). Cette technique fonctionne parfaitement mais ma méthode est actuellement incomplete : elle ne gère pas les tableaux. Je l'ai en effet amputée pour la rendre un peu plus simple à comprendre.
La seconde est toute simple : nous transformons l'objet en un string encodé en json, puis nous transformons ce string en objet. Boom, nous avons un clone sur toute sa profondeur ! Malheureusement, comme vous pouvez le voir, la fonction n'a pas été sérialisée, et est donc absente de notre clone.
La methode parfaite ?
Maintenant que cela est dit, laissez- moi vous dire quelque chose : la méthode boucle avec recursion que j'ai présenté présente une faille : elles ne gerent pas par les objets issus de classes custom, ces derniers apparaîtront sous la forme "objet".
La solution "ultime" est donc de partir de cette méthode boucle avec recursion et ajouter (en plus des arrays) vos différents types d'objets pour traiter tous les cas de figure qui peuvent apparaitre dans votre application. Cela vous créera une fonction de clonage personnalisée et "parfaite" pour votre application !