Qu'est-ce que JavaScript ?
Au-delà des idées reçues : le nom, la spécification (TC39/ECMAScript), les moteurs, et pourquoi JavaScript est un langage compilé.
Vous ne connaissez pas encore JS. Moi non plus, pas totalement. Personne ne le connaît vraiment. Mais nous pouvons tous apprendre à mieux le connaître, et cela commence par défaire quelques mythes tenaces. Avant de plonger dans la syntaxe, Kyle Simpson consacre tout un chapitre à une question qui paraît triviale et ne l'est pas : qu'est-ce que JavaScript, au juste ?
La réponse exige de clarifier des détails de « régie » que tout développeur devrait connaître : d'où vient le nom, qui décide de ce qu'est le langage, ce qui est du JS standard et ce qui ne l'est pas, et pourquoi du code écrit en 1995 fonctionne encore aujourd'hui. C'est de l'identité du langage qu'il s'agit, et la comprendre change la manière dont on l'écrit.
Ce nom, JavaScript
Le nom JavaScript est probablement le nom de langage le plus mal compris de toute l'histoire de la programmation. Non, ce langage n'a aucun lien réel avec Java. Il n'est pas une « version script » de Java, ni réservé à de petits programmes jetables.
La vérité est plus prosaïque : le nom est un artefact marketing. Quand Brendan Eich conçut le langage chez Netscape, son nom de code était Mocha, puis en interne LiveScript. Au moment de le nommer publiquement, « JavaScript » l'emporta — parce que le langage visait un public de programmeurs Java, et que le mot « script » désignait alors à la mode les petits programmes légers que l'on embarquait dans les pages de ce nouveau « web ». On aurait tout aussi bien pu l'appeler « WebJava ».
Les ressemblances de surface entre le code JS et le code Java (les accolades { et } pour délimiter un bloc, le ; pour ponctuer une instruction) ne viennent pas d'une parenté : elles viennent du fait que les deux langages ciblaient des développeurs habitués à la syntaxe du C (et, dans une certaine mesure, du C++).
Note
Le lien Java/JavaScript va même jusqu'au juridique : Oracle (via Sun, qui avait racheté la marque à Netscape) détient toujours la marque déposée « JavaScript ». Elle n'est presque jamais défendue. C'est l'une des raisons pour lesquelles l'abréviation JS s'est imposée — et pourquoi le nom officiel du langage est tout autre.
Le nom officiel, celui qui est spécifié par le comité TC39 et formalisé par l'organisme de normalisation ECMA, est ECMAScript (ES). Et depuis 2016, ce nom porte un suffixe d'année de révision : ECMAScript 2019, abrégé ES2019. Autrement dit, le JavaScript qui tourne dans votre navigateur ou dans Node.js est une implémentation de la norme ES20xx.
Piège courant
N'employez jamais des termes comme « JS6 » ou « ES8 » pour désigner le langage : ils n'entretiennent que la confusion. Tenez-vous-en à « ES20xx » (par exemple ES2020) ou simplement « JS ».
Comme le résume joliment Jeremy Keith : « Java est à JavaScript ce que le jambon est au hamster. »
La spécification : une seule, plusieurs implémentations
Qui décide de ce qu'est JavaScript ? Le TC39, le comité technique de pilotage qui gère le langage. Sa tâche première est de maintenir la spécification officielle (specification), où sont définis la syntaxe et le comportement de chaque fonctionnalité. Le comité se réunit régulièrement, vote les changements convenus, puis les soumet à ECMA.
Le TC39 compte entre 50 et 100 personnes, issues d'entreprises investies dans le web : fabricants de navigateurs (Mozilla, Google, Apple) et de matériel (Samsung, etc.). Tous sont volontaires, même si beaucoup sont salariés de ces sociétés.
Le processus par étapes (stages 0 à 4)
Toute proposition d'ajout au langage progresse à travers un processus en cinq étapes (stages) — numéroté de 0 à 4, parce que, programmeurs obligent, on compte à partir de zéro.
| Étape | Signification |
|---|---|
| Stage 0 | Un membre du TC39 juge l'idée digne d'intérêt et la « parraine ». |
| Stage 1 | La proposition est formellement à l'étude. |
| Stage 2 | La syntaxe et la sémantique se précisent. |
| Stage 3 | La proposition est mûre ; les implémenteurs peuvent l'ajouter. |
| Stage 4 | Éligible à la prochaine révision annuelle du langage. |
Une idée lancée sur un blog ou les réseaux sociaux par quelqu'un d'extérieur au comité n'est même pas « stage 0 » : c'est du pré-stage 0. Il faut qu'un membre du TC39 accepte de la parrainer pour qu'elle entre officiellement dans le processus. Le trajet complet, de l'idée au standard, peut prendre de quelques mois à plusieurs années.
À retenir
Contrairement à un mythe tenace, il n'existe pas plusieurs versions de JavaScript dans la nature. Il y a un seul JS, le standard officiel maintenu par TC39 et ECMA. À l'époque où Microsoft maintenait sa version dérivée et rétro-ingénierée, « JScript », on pouvait parler de versions multiples. Ces jours sont révolus depuis longtemps.
Tous les grands fabricants se sont engagés à maintenir leurs implémentations conformes à cette unique spécification. Les moteurs implémentent les nouveautés à des rythmes différents, mais jamais le moteur V8 (celui de Chrome) ne devrait implémenter une fonctionnalité de façon incompatible avec SpiderMonkey (celui de Mozilla). C'est la promesse fondatrice : vous apprenez un seul JS, et vous pouvez compter sur ce même JS partout.
JS standard ou ajouts de l'environnement ?
Voici un piège classique. Ce code est-il un programme JS ?
alert("Bonjour, JS !"); Cela dépend de votre point de vue. La fonction alert(..) ne figure pas dans la spécification ECMAScript : elle est fournie par les environnements web. Les environnements d'exécution — moteurs des navigateurs, Node.js, etc. — ajoutent dans la portée globale de vos programmes des API qui leur sont propres.
Une foule d'API « qui ressemblent à du JS » sont en réalité des API de l'environnement : fetch(..), getCurrentLocation(..), getUserMedia(..) côté navigateur ; des centaines de méthodes comme fs.write(..) côté Node.js. L'exemple le plus universel est console.log(..) (et toutes les méthodes console.*) : non spécifié par JS, mais défini par à peu près tous les environnements, par consensus.
// console.log et alert : ils OBEISSENT a la syntaxe JS,
// mais ce sont des "invites", pas du JS officiel.
console.log("Je suis un appel de fonction JS valide...");
alert("...mais alert lui-meme n'est pas du JS."); Ces fonctions sont des appels JS valides — elles obéissent aux règles syntaxiques du langage —, mais leur comportement est contrôlé par l'environnement, pas par le moteur JS. La distinction est cruciale : la plupart des plaintes « JS est tellement incohérent d'un navigateur à l'autre ! » concernent en réalité des différences d'environnement, pas le langage lui-même.
Attention
La console des outils de développement (le REPL, Read-Evaluate-Print-Loop) n'est pas un environnement JS pur. Ces outils privilégient l'expérience développeur (DX), pas la fidélité à la spécification. Selon les navigateurs, une déclaration var au niveau global, la prise en compte de "use strict";, le comportement de this… peuvent y différer du traitement d'un vrai fichier .js. Considérez la console comme un environnement « JS-friendly », pas comme une référence de sémantique exacte.
Multi-paradigme
Un paradigme est une approche large, presque universelle, de la façon de structurer le code. Les grandes familles sont :
- Procédural : le code progresse de haut en bas, comme une suite linéaire d'opérations regroupées en procédures.
- Orienté objet (OO/classes) : on regroupe logique et données dans des unités appelées classes.
- Fonctionnel (FP) : on organise le code en fonctions (des calculs purs) et en adaptations de ces fonctions traitées comme des valeurs.
Certains langages penchent fortement d'un côté : C est procédural, Java et C++ sont presque entièrement orientés classes, Haskell est fonctionnel de part en part. JavaScript, lui, est résolument multi-paradigme. Vous pouvez écrire du code procédural, orienté classes ou fonctionnel — et faire ces choix ligne par ligne, plutôt que d'être enfermé dans un choix unique pour tout le programme.
Rétro-compatibilité, mais pas l'inverse
L'un des principes les plus fondamentaux qui guident JavaScript est la préservation de la rétro-compatibilité (backwards compatibility). Beaucoup confondent ce terme avec un autre, voisin mais différent : la compatibilité ascendante (forwards compatibility). Démêlons-les.
La rétro-compatibilité signifie qu'une fois que quelque chose est accepté comme du JS valide, aucun changement futur du langage ne le rendra invalide. Du code écrit en 1995, aussi primitif soit-il, doit encore fonctionner aujourd'hui. Comme le proclament les membres du TC39 : « on ne casse pas le web ! » C'est un engagement rarissime en informatique, étalé sur près de trente ans.
Ce choix a un coût énorme : il place une barre très haute pour tout changement. Toute décision devient quasi permanente, erreurs comprises. Une fois dans JS, une fonctionnalité ne peut presque jamais en sortir, car cela risquerait de casser des programmes — même quand on aimerait vraiment, vraiment, la retirer.
La compatibilité ascendante est l'inverse : ce serait la garantie qu'un programme utilisant une nouveauté ne casse pas s'il tourne sur un moteur plus ancien. JS n'est PAS compatible ascendant, malgré le mythe contraire. HTML et CSS, eux, le sont : un navigateur de 2010 qui rencontre une propriété CSS de 2019 inconnue se contente de l'ignorer et continue. JS ne peut pas se le permettre.
Note
Pourquoi cette asymétrie ? HTML et CSS sont déclaratifs : sauter une déclaration inconnue a peu d'impact sur le reste. Mais ignorer silencieusement une instruction (ou même une expression !) dans un langage de programmation sèmerait le chaos : impossible de garantir qu'une partie ultérieure du programme n'attendait pas le résultat de la partie sautée.
Franchir l'écart : transpilation et polyfill
Puisque JS n'est pas compatible ascendant, il existe toujours un écart potentiel entre le code que vous voulez écrire (avec les dernières fonctionnalités) et le plus vieux moteur que votre site doit encore supporter. Exécuter une fonctionnalité ES2019 sur un moteur de 2016 fera très probablement planter le programme. Deux outils comblent cet écart, selon sa nature.
La transpilation pour la syntaxe
Pour une syntaxe nouvelle et incompatible, la solution est la transpilation (transpiling) : un outil convertit le code source d'une forme à une autre, tout en restant du code source textuel. Le transpileur le plus répandu est Babel. Vous écrivez la syntaxe moderne dans vos sources ; l'outil produit une version équivalente en syntaxe plus ancienne pour le déploiement.
// Ce que vous ECRIVEZ : let a une portee de bloc (ES6+).
if (quelqueChose) {
let x = 3;
console.log(x);
} else {
let x = 4;
console.log(x);
} // Ce que Babel PRODUIT pour un moteur pre-ES6 :
// deux variables aux noms uniques, meme resultat.
var x$0, x$1;
if (quelqueChose) {
x$0 = 3;
console.log(x$0);
} else {
x$1 = 4;
console.log(x$1);
} Pourquoi se donner cette peine plutôt que d'écrire directement deux variables et d'éviter let ? Parce qu'il est fortement recommandé d'utiliser la version la plus récente du langage : le code reste propre et communique le mieux son intention. Concentrez-vous sur la syntaxe moderne, et laissez les outils produire la version compatible ascendant.
Le polyfill pour les API manquantes
Si l'écart concerne non pas la syntaxe mais une méthode d'API récemment ajoutée, la solution est le polyfill (aussi appelé shim) : on fournit une définition de la méthode manquante, qui se comporte comme si le vieil environnement l'avait nativement.
// Polyfill simplifie de Promise.prototype.finally (ES2019).
// Le if protege : on ne definit QUE si la methode manque.
if (!Promise.prototype.finally) {
Promise.prototype.finally = function f(fn) {
return this.then(
function t(v) {
return Promise.resolve(fn()).then(function () {
return v;
});
},
function c(e) {
return Promise.resolve(fn()).then(function () {
throw e;
});
}
);
};
} Le if est essentiel : dans un environnement récent où finally existe déjà, le bloc est silencieusement sauté ; dans un vieil environnement, le polyfill prend le relais. Babel détecte d'ailleurs souvent les polyfills nécessaires et les ajoute pour vous.
Astuce
Transpilation et polyfill devraient faire partie de la chaîne de production de tout projet JS. Écrivez toujours avec les fonctionnalités les plus adaptées pour exprimer votre intention — en général, la dernière version stable — et n'altérez jamais la lisibilité en ajustant l'écart à la main. C'est précisément le rôle des outils.
JavaScript est-il interprété ou compilé ?
Voici le débat le plus ancien autour de JS. L'opinion majoritaire le range parmi les langages interprétés (de script). L'argument de Simpson est plus tranchant : en esprit, JS est un langage compilé, et cette distinction n'est pas qu'une querelle de vocabulaire — elle change concrètement la façon dont les erreurs vous sont signalées.
Historiquement, un langage interprété s'exécute ligne par ligne, de haut en bas, sans passe préalable sur l'ensemble du programme. Conséquence : une erreur ligne 5 ne sera découverte qu'après l'exécution des lignes 1 à 4. À l'opposé, les langages qui passent d'abord par une étape de traitement — l'analyse syntaxique (parsing) — détectent une syntaxe cassée ligne 5 avant que rien ne s'exécute.
function exemple() {
console.log("Cette ligne ne s'affichera JAMAIS.");
var x = ; // <-- erreur de syntaxe ligne 3
}
exemple();
// Le moteur ANALYSE tout le programme d'abord :
// il refuse de demarrer et signale l'erreur de syntaxe.
// Le console.log de la ligne 2 ne s'execute pas. Ce comportement est révélateur : si JS était purement interprété ligne par ligne, le console.log s'exécuterait avant que l'erreur ligne 3 soit rencontrée. Or il ne s'exécute pas. La spécification exige que ces early errors — erreurs déterminées statiquement, comme un nom de paramètre dupliqué (en mode strict) — soient rapportées avant le début de l'exécution. Ce qui est impossible sans avoir d'abord analysé tout le code.
Du parsing à l'exécution
Tous les langages compilés sont analysés (parsés) ; un langage parsé est donc déjà bien avancé sur la route de la compilation. Après le parsing, l'étape restante est la génération de code : produire une forme exécutable. Voici le parcours réel d'un programme JS dans le moteur :
1. Le code quitte l'editeur, est transpile (Babel),
empaquete (Webpack), puis livre au moteur.
2. Le moteur l'analyse en un AST (arbre syntaxique abstrait).
3. L'AST devient un bytecode binaire, raffine par le
compilateur optimisant JIT (Just-In-Time).
4. La machine virtuelle JS execute enfin le programme. Le code source JS est donc parsé, converti en une forme binaire optimisée (un bytecode confié à la « machine virtuelle JS »), puis exécuté — souvent avec plusieurs passes d'optimisation JIT (Just-In-Time). Le moteur ne repasse pas en mode ligne par ligne : ce serait terriblement inefficace. En esprit, sinon dans la lettre, c'est de la compilation. Et l'enjeu reste le même : parce que JS est compilé, vous êtes informé des erreurs statiques avant l'exécution. Un modèle d'interaction nettement plus utile que le mode « script » traditionnel.
Note
Le débat est plus subtil qu'il n'y paraît : la machine virtuelle qui exécute le bytecode JS « interprète » en un sens ce bytecode. Mais alors Java, et une douzaine de langages tournant sur la JVM, seraient eux aussi « interprétés » — ce qui contredit l'affirmation courante qu'ils sont compilés. Les deux questions sont en fait étroitement liées.
WebAssembly, en marge
La performance a beaucoup guidé l'évolution de JS. En 2013, des ingénieurs de Mozilla portèrent le moteur de jeu Unreal 3 du C vers JS, à 60 images par seconde, grâce à un sous-ensemble du langage nommé ASM.js, conçu pour signaler au moteur des informations de typage permettant des optimisations.
De ces travaux est né WebAssembly (WASM) : un format de représentation proche de l'assembleur, qui permet à des programmes non-JS (C, Go, Rust…) de tourner dans le moteur JS en contournant l'étape de parsing/compilation (faite en amont, ahead of time). WASM allège ainsi la pression pour ajouter à JS des fonctionnalités destinées uniquement à des programmes transpilés depuis d'autres langages.
Deux points à retenir : WASM n'est pas réservé au web (il évolue vers une machine virtuelle multiplateforme) et WASM n'est pas du JS. Ironie du sort, JS est l'un des langages les moins adaptés pour produire du WASM, car ce dernier repose massivement sur le typage statique. Et non : WASM ne remplacera pas JS ; il augmente ce que le web peut accomplir.
Le mode strict
Avec ES5, en 2009, JS a introduit le mode strict (strict mode) : un mécanisme opt-in pour encourager de meilleurs programmes. Plus de dix ans après, son caractère optionnel fait qu'il n'est toujours pas le défaut.
Pourquoi l'activer ? Le mode strict n'est pas une restriction de ce que vous pouvez faire, mais un guide vers la meilleure façon de faire les choses — celle qui donne au moteur les meilleures chances d'optimiser le code. La plupart de ses contrôles prennent la forme d'early errors (rejetées à la compilation) : interdiction de deux paramètres de même nom, par exemple. D'autres ne sont observables qu'à l'exécution, comme this qui vaut undefined par défaut au lieu de l'objet global.
On l'active par fichier, avec un pragma spécial — rien d'autre que des commentaires ou des espaces ne doit le précéder :
// seuls des commentaires ou des espaces sont permis
// avant le pragma use-strict
"use strict";
// tout le reste du fichier s'execute en mode strict Attention
Méfiance : même un ; égaré tout seul avant le pragma le rend inopérant. Aucune erreur n'est levée — il est légal d'avoir une chaîne littérale en position d'instruction —, mais le mode strict ne s'active pas silencieusement.
On peut aussi l'activer par fonction, avec les mêmes règles :
function quelquesOperations() {
// espaces et commentaires sont permis ici
"use strict";
// tout ce code s'execute en mode strict
} En pratique, le mode strict est devenu le défaut de facto : presque tout le code transpilé finit en mode strict, et les modules ES6 l'imposent automatiquement. Voyez-le comme un linter qui vous rappelle comment JS devrait être écrit. Si vous vous sentez menotté et que vous cherchez à le contourner, c'est le signal qu'il faut repenser votre approche, pas combattre le mode strict.
À retenir
- JavaScript ≠ Java : le nom est un coup marketing. Le nom officiel est ECMAScript (ES), suffixé de l'année (ES2019, ES2020…). Dites « JS » ou « ES20xx », jamais « ES8 ».
- Une seule spécification, plusieurs implémentations : le TC39 gère la spec via un processus en stages 0 à 4 ; les moteurs (V8, SpiderMonkey…) doivent tous s'y conformer. Apprenez un JS, fiez-vous-y partout.
- Distinguez le JS standard de l'environnement :
console.log,alert, le DOM,fs… ne sont pas du JS, mais des API ajoutées par le navigateur ou Node.js. - Rétro-compatible, mais pas compatible ascendant : le code de 1995 tourne encore ; le code récent casse sur un vieux moteur. Comblez l'écart avec la transpilation (Babel, pour la syntaxe) et les polyfills (pour les API).
- JS est compilé (en esprit) : le code est analysé en un AST avant toute exécution, d'où la détection des erreurs de syntaxe en amont. JS est aussi multi-paradigme (procédural, OO, fonctionnel).
- Activez le mode strict : un guide vers du code optimisable, déjà de facto le défaut via les modules ES6 et la transpilation.