Le JavaScript est un des langages les plus utilisés sur le web aujourd’hui. Sortie officiellement en décembre 1995, c’est grâce à ce langage que sont créées toutes les interactions dynamiques (ou presque) sur les pages web aujourd’hui. Depuis la sortie de Node.JS, son utilisation est même possible directement sur le serveur.
Je ne vais pas m’étendre sur le fonctionnement précis du langage et son paradigme de développement (prototypage, typage faible…).
Une chose importante à savoir est que toute assignation créé une référence à la variable et pas une copie. Ce comportement d’assignation est plutôt standard dans la programmation mais en JavaScript il est assez facile de se perdre dans le contexte (closure, callback, promises…) et il faut donc faire encore plus attention.
Chaque variable créé a une portée correspondant à son bloc d’instruction mais les références peuvent influer sur le contexte de niveau supérieur ce qui peut être dangereux pour le fonctionnement de l’application.
Un exemple concret
J’ai récemment créé un petit script pour visualiser le contenu de la base localStorage attachée à une page web pour aider un client à détecter ses problèmes de connexion.
C’est un conteneur de donnée persistent attaché au site sur lequel l’utilisateur navigue (chaque domaine à son propre conteneur). Il est attaché à l’objet window
dans window.localStorage
et son usage est très simple car il fonctionne comme un tableau :
window.localStorage['key'] = value;
var key = window.localStorage['key'];
window.localStorage.clear(); //Pour vider les données locales
Cette spécification est maintenant bien supportée sur les navigateurs du marché ce qui en fait un outil intéressant dans le développement d’applications riches.
Pour visualiser le contenu de cette petite base de donnée, j’ai écris le code suivant :
function display() {
var storage = window.localStorage;
for (var i in storage) {
if (typeof storage[i] === 'string') {
storage[i] = JSON.parse(storage[i]);
}
}
//Transformation en JSON visualisable
return JSON.stringify(storage, null, '\t');
}
Le problème avec cette approche est que l’assignation storage[i]
met à jour directement le contenu de window.localStorage
. La création de la variable storage
créé une référence à la petite base de donnée et pas une copie des données.
Pour « casser » la référence et obtenir une copie propre manipulable sans impact, il y a plusieurs méthodes :
Object.create
une fonction introduite en JavaScript 1.8.5 et maintenant supporté par les principaux navigateurs ;- Manipulation du prototype ce qui revient à émuler le comportement d’
Object.create
.
Voici la version finale de ma fonction pour visualiser le contenu de window.localStorage
:
function clone(object) {
function F() {}
F.prototype = object;
return new F();
}
function display() {
//Ou var storage = Object.create(window.localStorage);
var storage = clone(window.localStorage);
for (var i in storage) {
if (typeof storage[i] === 'string') {
storage[i] = JSON.parse(storage[i]);
}
}
return JSON.stringify(storage, null, '\t');
}