Writing
Blog post

JavaScript a été créé en dix jours

10 avril 2023

Brendan Eich a créé JavaScript en dix jours. Cela commençait comme un moyen d'apporter de l'interactivité au navigateur, en somme un outil de hackeur, et c'est aujourd'hui le langage de programmation le plus populaire au monde. Comme l'anglais, son usage est divers et s'adapte sans cesse à de nouvelles situations.

Je voudrais retracer cette polyvalence en un seul mot : this.

Si vous venez d'un autre langage orienté objet et que vous vous mettez sérieusement à JavaScript, vous tombez tôt ou tard sur l'étrangeté de this. Il change de contexte. Il est déterminé à l'exécution, de façon implicite ou explicite, selon le style d'écriture de la fonction et selon que vous êtes ou non en mode strict. Il ne renvoie pas seulement à l'instance d'objet.

Ce comportement a facilité la manipulation du DOM dans les années 1990, et jQuery s'y appuie largement. Mais aux débuts de React, ce comportement m'a vraiment déboussolé. Considérez cet exemple :

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this); 
  }
 
  handleClick() {
    console.log(this); // affiche l'instance du composant
  }
 
  render() {
    return <button>Click me</button>;
  }
}

Avant que React n'introduise les composants fonctionnels et les hooks, un composant devait étendre la classe React.Component pour utiliser les méthodes de cycle de vie. Un cas courant : ajouter un écouteur d'événement après le rendu du DOM, ou le retirer après le démontage. Plutôt que de tout fourrer dans une méthode render, qui devrait s'occuper du rendu, il était logique de placer le gestionnaire d'événement dans une méthode propre.

Mais voici le hic : le composant de rendu crée un élément du DOM qui, par l'interaction de l'utilisateur, ajoute un événement à la file. Le contexte de this à cet instant n'est pas le composant React qui a fait le rendu, mais l'élément du DOM lui-même. C'est pourquoi un binding explicite vers le composant est nécessaire :

this.handleClick = this.handleClick.bind(this); 

C'est si contre-intuitif que cela a alimenté de longs et vifs débats sur la question de savoir si JavaScript peut vraiment être considéré comme un langage orienté objet. Le verdict général est, je crois, « oui », mais je ne fais pas autorité. JS prend en charge objets, classes, héritage, encapsulation et polymorphisme. Mozilla va jusqu'à qualifier JavaScript de « heavily object oriented ». Même les fonctions sont une sorte d'objet en JavaScript.

Mais this essayait simplement d'être utile.

ES6 et les hooks

Le langage évolue plus vite que la modélisation, dans la parole comme dans le logiciel. Depuis l'introduction des hooks dans React 16.8, le standard de l'industrie est d'écrire des composants fonctionnels :

import React from 'react';
 
function MyComponent() {
  return (
    <button => console.log(this)}>Click me</button>
  );
}

Dans ce nouvel exemple, this s'affiche comme undefined, non pas comme l'élément du DOM. Cela n'a rien à voir avec une nouveauté de React, mais avec une caractéristique d'ES6. À onClick est passée une fonction fléchée, qui n'a pas de contexte this propre. Pour ce cas d'usage, cela rend les choses bien plus lisibles. Voilà donc un exemple d'évolution de la spécification du langage.

Mais l'évolution de son usage, ici autour de l'introduction des hooks, me paraît tout aussi intéressante. Les billets de blog sur les hooks insistent souvent sur la réutilisabilité ou la concision pour expliquer pourquoi les hooks sont « géniaux ». Or s'en tenir aux fonctions réduit ce qu'un développeur doit savoir, ce qui lui permet de se concentrer sur le rendu de l'interface. Nous n'avons pas besoin d'un monde rempli d'ontologues.

Respectez le « bête »

La conversation détendue du quotidien est pleine de présupposés. Si j'écris un script pour trouver un élément bouton et que je veux que « celui-ci » se désactive après un clic, je m'attends à ce que l'interpréteur comprenne ce que je veux dire. On dit que les hypothèses font de vous et de moi des ânes, mais ceux qui le disent ont des papas riches et pas de deadlines.

React doit en bonne partie sa popularité à une certaine gradation (plutôt qu'une séparation) des préoccupations, depuis les composants de données « plus malins » qui s'occupent du fetching, du routage et de la gestion d'état, presque toujours uniques à une application, jusqu'aux composants « bêtes » qui rendent l'interface utilisateur. Ce spectre du malin au bête ne porte pas sur l'intelligence ou la compétence du développeur, mais sur le degré de contexte dynamique d'un composant. La capacité d'échelle et la popularité de React reposent sur ces composants bêtes. Le contexte y est explicite sous forme de props, jusqu'à ce qu'il ne le soit plus. Et là, je deviens critique.

Pour aller plus loin

Derniers articles