# 🇫🇷 Un Proxy en JS, c'est bien pratique
Tout d'abord, tous mes voeux pour vous et vos proches. Que cette nouvelle année soit pleine de nouveautés, de curiosités et surtout l'occasion de se retrouver plus souvent en famille et entre amis. 😘
Pour mon 1er article de l'année (en français car je 'ai pas le courage ce matin de faire l'exercice en anglais), j'ai fait un peu de "Vanilla JS" pour quelques expérimentations et j'ai joué avec les proxies (en JavaScript). Je vais donc vous donner un cas d'usage d'un Proxy JS: J'ai été et suis encore très fan de Backbone, et ce que j'aime par dessus tout dans Backbone ce sont les models (opens new window). Donc, mon expérimentation consiste en l'écriture des prémices d'un successeur des Backbone Models (c'est très présomptueux, mais c'est Dimanche, soyons fous 🤪)
👋 c'est une expérimentation, et je n'ai pas encore exploré toutes les possibilités du Proxy, donc n'hésitez pas à proposer des corrections, améliorations, etc. ...
# Mais qu'est-ce qu'un proxy en JavaScript?
Sur le site de Mozilla, vous trouverez cette définition:
The Proxy object is used to define custom behavior for fundamental operations (e.g. property lookup, assignment, enumeration, function invocation, etc).
Si je m'essaye à une définition en français, je dirais que le Proxy est un objet qui réagit à différents événements, comme par exemple le changement de valeur d'une propriété.
# 1er Proxy
Ce qui m'intéresse essentiellement aujourd'hui, ce sont les propriétés de mon objet (autrement dit les getters et les setters). Un Proxy est un objet qui "englobe" un autre objet. On pourrait dire que le Proxy est un wrapper et nous appellerons l'"autre objet" la target. Le Proxy possède aussi un objet handler qui "possède" toutes les fonctions qui sont déclenchées lors de certaines actions (on parle aussi de trap), comme par exemple [handler.get()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/get)
ou [handler.set()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/set)
.
Par exemple, je vais utiliser le code ci-dessous dans la console de mon navigateur:
let johnDoe = new Proxy({ // Object
firstName: "John",
lastName: "Doe"
}, { // traps handler
get: function(target, property) {
return `👋${target[property]}🖖`
},
set: function(target, property, value) {
console.log("old value:", target[property])
console.log("new value:", value)
target[property] = value
return true
}
})
Et le résultat va être le suivant:
Je trouve ça plutôt sympa, pas vous? Cela peut être très pratique. J'ai donc voulu aller plus loin, toujours avec mon idée de models en tête.
# Donc, les prémices de mon modèle
J'ai bien bricolé, mais à chaque fois le résultat obtenu ne me convenait pas. Je me suis arrêté un moment, pris le temps de feuilleter l'excellent livre Exploring ES6 du non moins excellent Axel Rauschmayer (opens new window)
👋 Tous les livres d'Axel sont excellents
L'extrait qui ma rendu service est ici: https://exploringjs.com/es6/ch_proxies.html#sec_proxy-use-cases (opens new window) au § 28.4.2. Axel explique comment transformer un Proxy en constructor
(et donc cela vous donne la possibilité d'en hériter):
function PropertyChecker() { }
PropertyChecker.prototype = new Proxy(···);
class Point extends PropertyChecker {
constructor(x, y) {
super();
this.x = x;
this.y = y;
}
}
# Petit détour avant de continuer: construisons un WebComponent
Pour afficher les modifications de mon futur modèle, je vais utiliser un web component (fait from scratch, mais c'est ensuite adaptable). Donc, créez une page index.html
avec le code suivant:
<!doctype html>
<html lang="en">
<head>
<title>have fun with web components</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<style></style>
</head>
<body>
<my-buddy
id="john-doe"
avatar="😎"
firstName="???"
lastName="???">
</my-buddy>
</body>
<script>
class MyBuddy extends HTMLElement {
connectedCallback() {
this.attachShadow({mode: 'open'})
this.render()
}
render() {
this.shadowRoot.innerHTML=`
<h1>
${this.getAttribute("avatar")} ${this.getAttribute("firstName")} ${this.getAttribute("lastName")}
</h1>
`
}
}
customElements.define('my-buddy', MyBuddy)
</script>
</html>
# Puis ajoutons notre modèle
Ensuite, toujours dans index.html
, ajoutons notre Proxy transformé en constructor
(BuddyProxy
) et notre modèle Buddy
qui hérite de BuddyProxy
function BuddyProxy() {}
BuddyProxy.prototype = new Proxy({
on: function(eventName, eventHandler) {
this[eventName]=eventHandler
}
},
{
set: function(target, property, value) {
// old property value: target[property]
// new property value: value
target[property] = value
// if the `change` method exists, call it
if (target.change) target.change(target, property)
return true
}
})
class Buddy extends BuddyProxy {
constructor(options) {
super()
Object.assign(this, options)
}
}
👋 Remarque: j'ai ajouté à la target
du Proxy, une méthode on(eventName, eventHandler)
qui va me permettre d'ajouter dynamiquement des méthodes à l'instance de mon modèle. et j'appelle cette méthode dans le set
du Proxy (ex: si une méthode change
existe: if (target.change) target.change(target, property)
).
Voici un exemple:
bob.on("change", (model, property) => {
console.log(` this ${property} has changed: ${model[property]}`)
})
il y a différentes façons de faire ceci, je le rappelle, c'est une expérimentation.
Sauvegardez votre page et "ouvrez" la dans un navigateur:
Alors le chemin est long avant de rivaliser avec Backbone, mais cela va me faire un nouveau side project sympa.
Bonne soirée et bonne reprise demain.
Last Articles
- 🇫🇷 Type Result en Kotlin | 2020-10-31 | Kotlin
- 🇫🇷 Type Result en Kotlin | 2020-10-31 | Kotlin
- 🇬🇧 Every GitLab Page deserves a real CI/CD | 2020-07-23 | GitLab CI
- 🇫🇷 Lit-Element, commencer doucement | 2020-07-20 | WebComponent
- 🇬🇧 Build quickly and host easily your Docker images with GitLab and GitLab CI | 2020-06-02 | GitLab CI
- 🇬🇧 Deploy quickly on Clever Cloud with GitLab CI | 2020-05-31 | GitLab CI
- 🇫🇷 Borg Collective, mes jouets pour apprendre Knative | 2020-05-30 | Knative
- 🇬🇧 Borg Collective, Toys to learn Knative | 2020-05-30 | Knative
- 🇫🇷 M5Stack, une petit device IOT bien sympathique, programmable en Python | 2020-05-09 | IOT
- 🇫🇷 Knative, l'outil qui rend Kubernetes sympathique | 2020-05-02 | kubernetes