Une réintroduction à JavaScript

  • Raccourci de la révision : Web/JavaScript/Une_réintroduction_à_JavaScript
  • Titre de la révision : Une réintroduction à JavaScript
  • ID de la révision : 445247
  • Créé :
  • Créateur : tregagnon
  • Version actuelle ? Non
  • Commentaire

Contenu de la révision

 

Introduction

Pourquoi une réintroduction ? Parce que JavaScript peut raisonnablement se targuer d'être le langage de programmation le plus incompris au monde. Bien que souvent raillé comme étant un simple jouet, derrière sa simplicité désarmante se cachent certaines fonctionnalités de langage très puissantes. On a vu au cours de l'année 2005 l'apparition d'un certain nombre d'applications JavaScript de tout premier plan, ce qui montre qu'une connaissance approfondie de cette technologie est une compétence importante pour tout développeur Web.

Il peut être utile de commencer avec une idée de l'histoire de ce langage. JavaScript a été créé en 1995 par Brendan Eich, un ingénieur chez Netscape, et fourni pour la première fois avec Netscape 2 début 1996. Il était au départ censé s'appeler LiveScript, mais a été renommé par une décision marketing néfaste dans le but de capitaliser sur la popularité du langage Java de Sun Microsystems, malgré le fait qu'ils n'aient que très peu en commun. Cela n'a jamais cessé d'être une source de confusion.

Quelques mois plus tard, Microsoft a lancé avec Internet Explorer 3 une version du langage globalement compatible, appelée JScript. Netscape a soumis le langage à l'Ecma International, une organisation de normalisation européenne, ce qui a abouti à la première édition du standard ECMAScript en 1997. Ce standard a reçu une mise à jour importante appelée ECMAScript edition 3 en 1999, et n'a plus bougé depuis. La quatrième édition a été abandonnée suite à des différents portants sur la complexité du langage. De nombreuses sections de la quatrième édition ont été utilisées pour servir de fondation à la cinquième édition d'ECMAScript, publiée en décembre 2009.

Cette stabilité est une excellente nouvelle pour les développeurs, parce qu'elle a donné aux différentes implémentations tout le temps nécessaire pour s'y adapter. Je me concentrerai presque exclusivement sur le dialecte de l'édition 3. Pour faciliter la lecture, le terme JavaScript sera cependant utilisé tout au long de cet article.

Contrairement à la plupart des langages de programmation, JavaScript n'a pas de concept d'entrée ou de sortie. Il est conçu pour s'exécuter comme un langage de script dans un environnement hôte, et c'est à cet environnement de fournir des mécanismes de communication avec le monde extérieur. L'environnement hôte le plus commun est un navigateur, mais des interpréteurs JavaScript existent également dans Adobe Acrobat, Photoshop, le moteur de widgets de Yahoo!, et même au sein d'environnements côté serveur.

Aperçu

JavaScript est un langage dynamique orienté objet ; il dispose de différents typages, opérateurs, objets coeurs et méthodes. Sa syntaxe s'inspire des langages Java et C, donc de nombreuses structures de ces langages s'appliquent également à JavaScript. À la différence de ces langages, JavaScript n'a pas de classes ; au lieu de cela, la fonctionnalité des classes est reprise par les prototypes d'objet. L'autre grande différence tient dans le fait que les fonctions sont des objets, ce qui leur permet de contenir du code executable et d'être transmises comme n'importe quel objet.

Commençons par nous intéresser à la brique de base de tout langage : les types. Les programmes en JavaScript manipulent des valeurs, et ces valeurs appartiennent toutes à un type. Les types JavaScript sont :

… oh, et Undefined et Null, qui sont relativement étranges. Et les tableaux (Arrays), qui sont une sorte particulière d'objets. Et les Dates et les expressions régulières (Regular Expressions), qui sont des également des objets, pour faire bonne mesure. Et pour être techniquement irréprochable, les fonctions sont aussi une sorte particulère d'objets. De sorte que le diagramme de types ressemble en fait plus à ceci :

  • Number
  • String
  • Boolean
  • Object
    • Function
    • Array
    • Date
    • RegExp
  • Null
  • Undefined

Enfin, il y a également quelques types d'erreurs. Les choses sont malgré tout beaucoup plus simples si on en reste au premier diagramme.

Les nombres

Les nombres en JavaScript sont « des valeurs au format IEEE 754 en double précision 64 bits », d'après la spécification. Les conséquences de ce choix sont intéressantes. Il n'y a par exemple pas de type entier en JavaScript, donc il vous faudra faire preuve d'un petit peu de prudence avec vos opérations arithmétiques si vous avez l'habitude de faire des maths en C ou en Java. Attendez-vous à obtenir des résultats comme :

0.1 + 0.2 = 0.30000000000000004

Les opérateurs numériques standards sont gérés, dont l'addition, la soustraction, le modulo (ou reste) arithmétique et ainsi de suite. Il y a également un objet natif qui n'a pas été mentionné jusqu'à présent, appelé Math, pour gérer des fonctions et constantes mathématiques plus avancées :

Math.sin(3.5);
d = Math.PI * r * r;

On peut convertir une chaîne en un nombre entier à l'aide de la fonction intégrée parseInt(). Elle reçoit la base de conversion comme second paramètre, que vous devriez toujours fournir :

> parseInt("123", 10)
123
> parseInt("010", 10)
10

Si vous n'indiquez pas la base, les résultats peuvent être surprenants dans les anciens navigateurs (pré-2013) :

> parseInt("010")
8

Cela se produit parce que la fonction parseInt a décidé de traiter la chaîne comme un nombre octal à cause du zéro initial.

Si vous désirez convertir un nombre binaire en un entier, changez simplement la base :

> parseInt("11", 2)
3

De la même manière, vous pouvez traiter les nombreux à virgule flottante à l'aide de la fonction intégrée parseFloat(), qui à la différence de sa cousine parseInt() utilise toujours la base 10.

Vous pouvez également utiliser l'opétateur unaire + pour convertir des valeurs en nombres :

> + "42"
42 

Une valeur spéciale appelée NaN (qui signifie "Not a Number", soit "pas un nombre") est renvoyée si la chaîne est non numérique :

> parseInt("hello", 10)
NaN

NaN est toxique : si vous fournissez cette valeur en entrée pour n'importe quelle opération mathématique, le résultat sera également NaN :

> NaN + 5
NaN

Vous pouvez la détecter à l'aide de la fonction intégrée isNaN :

> isNaN(NaN)
true

JavaScript dispose également de valeur spéciales pour l'infinité (Infinity) et l'infinité négative (-Infinity) :

> 1 / 0
Infinity
> -1 / 0
-Infinity

Vous pouvez tester les valeurs Infinity, -Infinity et NaN à l'aide de la fonction intégrée isFinite() :

> isFinite(1/0)
false
> isFinite(-Infinity)
false
> isFinite(NaN)
false
Note : Les fonctions parseInt() et parseFloat() traitent une chaîne jusqu'à ce qu'elles atteignent un caractère qui n'est pas valide pour le format numérique indiqué, puis renvoie le nombre traité jusqu'à ce point. Cependant, l'opérateur "+" convertit simplement la chaîne à NaN à partir du moment où la chaîne contient le moindre caractère non valide. Essayez simplement de traiter vous même la chaîne "10.2abc" avec chaque méthode dans la console afin de mieux comprendre les différences.

Les chaînes

Les chaînes en JavaScript sont des séquences de caractères. Plus précisément, elles sont des séquences de caractères Unicode, avec chaque caractère représenté par un nombre de 16 bits. Cette nouvelle devrait être bien accueillie par toute personne ayant eu affaire à des problèmes d'internationalisation.

Si vous voulez représenter un seul caractère, il suffit d'utiliser une chaînes de longueur 1.

Pour connaître la longueur d'une chaîne, utilisez sa propriété length :

> "hello".length
5

C'est notre première rencontre avec les objets JavaScript ! Est-ce que j'ai précisé que les chaînes étaient des objets également ? Elles ont aussi des méthodes :

> "hello".charAt(0)
h
> "hello, world".replace("hello", "goodbye")
goodbye, world
> "hello".toUpperCase()
HELLO

Autres types

JavaScript fait la distinction entre null, qui est un objet de type object indiquant une absence délibérée de valeur, et undefined qui est un objet de type undefined indiquant une valeur non initialisée — c'est-à-dire qui a n'a encore été assignée. Nous parlerons des variables plus tard, mais en JavaScript il est possible de déclarer une variable sans lui assigner de valeur. Si vous faites cela, le type de la variable est undefined.

JavaScript dispose d'un type booléen, dont les valeurs possibles sont true (vrai) et false (faux). L'un et l'autre sont des mots clés. Toute valeur peut être convertie en une valeur booléenne selon les règles suivantes :

  1. false, 0, la chaîne vide (""), NaN, null et undefined deviennent toutes false
  2. toutes les autres valeurs deviennent true

Cette conversion peut être faite de manière explicite à l'aide de la fonction Boolean() :

> Boolean("");
false
> Boolean(234);
true

Cependant, c'est rarement nécessaire, puisque JavaScript effectuera cette conversion silencieusement chaque fois qu'il attend une valeur booléenne, comme dans une instruction if (voir plus bas). Pour cette raison, on parle souvent simplement de valeurs « vraies » et « fausses » pour indiquer des valeurs devenant respectivement true et false lorsqu'elles sont converties en valeurs booléennes.

Les opérations booléennes comme && (et logique), || (ou logique) et ! (non logique) sont également gérées, comme on le verra plus bas.

Les variables

Les nouvelles variables en JavaScript sont déclarées à l'aide du mot clé var :

var a;
var name = "simon";

Si vous déclarez une variable sans lui assigner quoi que ce soit, sa valeur est undefined. should note the absence of block-scoping in JS

Les opérateurs

Les opérateurs numériques en JavaScript sont +, -, *, / et % (qui est l'opérateur de reste). Les valeurs sont assignées à l'aide de =, et il existe également des opérateurs d'assignation combinés comme += et -=. Ils sont équivalents à x = x opérateur y.

x += 5
x = x + 5

Vous pouvez utiliser ++ et -- respectivement pour incrémenter et pour décrémenter. Ils peuvent être utilisés comme opérateurs préfixes ou postfixes.

L'opérateur + se charge également de concaténer des chaînes :

> "hello" + " world"
hello world

Si vous additionnez une chaîne à un nombre (ou une autre valeur), tout est d'abord converti en une chaîne. Ceci pourrait vous surprendre :

> "3" + 4 + 5
345
> 3 + 4 + "5"
75

L'ajout d'une chaîne vide à quelque chose est une manière utile de la convertir en une chaîne.

Les comparaisons en JavaScript se font à l'aide de <, >, <= et >=. Ceux-ci fonctionnent tant pour les chaînes que pour les nombres. L'égalité est un peu moins évidente. L'opérateur double égal effectue une équivalence si vous lui donnez des types différents, ce qui donne parfois des résultats intéressants :

> "dog" == "dog"
true
> 1 == true
true

Pour éviter les calculs d'équivalences de types, utilisez l'opérateur triple égal :

> 1 === true
false
> true === true
true

Les opérateurs != et !== existent également.

JavaScript dispose également d'opérations bit à bit. Si vous en avez besoin, elles sont là.

Les structures de contrôle

JavaScript dispose d'un ensemble de structures de contrôles similaire aux autres langages de la famille du C. Les structures conditionnelles sont présentées avec if et else ; lesquels peuvent être chaînés si on le désire :

var name = "des chatons";
if (name == "des chiots") {
  name += " !";
} else if (name == "des chatons") {
  name += " !!";
} else {
  name = " !" + name;
}
name == "des chatons !!"

JavaScript dispose également de boucles while et do-while. Les premières sont bonnes pour des boucles basiques ; les secondes pour des boucles pour lesquelles vous voulez vous assurer que le corps de la boucle sera exécuté au moins une fois :

while (true) {
  // une boucle infinie !
}

do {
  var input = get_input();
} while (inputIsNotValid(input))

Les boucles for en JavaScript sont les mêmes qu'en C et en Java : elles permettent de fournir les informations de contrôle de la boucle en une seule ligne.

for (var i = 0; i < 5; i++) {
  // Sera exécutée cinq fois
}

Les opérateurs && et || utilisent une logique de court-circuit, ce qui signifie qu'ils exécuteront leur second opérande ou non selon la valeur du premier. C'est très utile pour vérifier qu'un objet n'est pas égal à null avant d'essayer d'accéder à ses attributs :

var name = o && o.getName();

Ou pour définir des valeurs par défaut :

var name = otherName || "default";

JavaScript propose également un opérateur ternaire pour les assignations conditionnelles en une ligne :

var permis = (age > 18) ? "oui" : "non";

L'instruction switch peut être utilisée pour différentes branches de code basées sur un nombre ou une chaîne :

switch(action) {
    case 'dessiner':
        dessine();
        break;
    case 'manger':
        mange();
        break;
    default:
        nerienfaire();
}

Si vous n'ajoutez pas d'instruction break, l'exécution va se poursuivre au niveau suivant. C'est rarement ce qui est désiré, en fait ça vaut même la peine de préciser dans un commentaire si la poursuite au cas suivant est délibérée pour aider au débogage :

switch(a) {
    case 1: // identique au cas 2
    case 2:
        mange();
        break;
    default:
        nerienfaire();
}

La clause default est optionnelle. Vous pouvez placer des expressions à la fois dans la partie switch et dans les cas à gérer si vous voulez ; les comparaisons entre les deux se font comme si on avait utilisé l'opérateur === :

switch(1 + 3):
    case 2 + 2:
        yay();
        break;
    default:
        narrivejamais();
}

Les objets

Les objets en JavaScript sont simplement des collections de paires nom-valeur. Dans ce sens, ils sont similaires aux :

  • dictionnaires en Python
  • hashs en Perl et Ruby
  • tables de hashing en C et C++
  • HashMaps en Java
  • tableaux associatifs en PHP

Le fait que cette structure de données soit si largement utilisée est un témoignage de sa polyvalence. Puisque tout (sauf les types de base) est un objet en JavaScript, tout programme écrit dans ce langage implique naturellement un grand nombre de recherches dans des tables de hashing. C'est une bonne chose que ce soit si rapide !

La partie « nom » est une chaîne JavaScript, tandis que la partie « valeur » peut être n'importe quelle valeur JavaScript, en ce compris d'autres objets. Cela permet de construire des structures de données de n'importe quel niveau de complexité arbitraire.

Il existe deux façons très simples de créer un objet vide :

var obj = new Object();

Et :

var obj = {};

Ces deux lignes sont sémantiquement équivalentes ; la seconde est appelée la syntaxe littérale d'objet, et est beaucoup plus pratique. Cette syntaxe n'existait pas dans les toutes premières version du langage, c'est pourquoi on voit tellement de code utilisant l'ancienne méthode.

Une fois l'objet créé, ses propriétés peuvent à nouveau être consultées de deux manières différentes :

obj.name = "Simon"
var name = obj.name;

Et…

obj["name"] = "Simon";
var name = obj["name"];

Ces lignes sont également sémantiquement équivalentes. La seconde méthode a l'avantage de fournir le nom de l'objet dans une chaîne, ce qui signifie qu'il peut être calculé au moment de l'exécution. Elle peut également être utilisée pour définir et lire des propriétés dont les noms sont des mots réservés :

obj.for = "Simon"; // erreur de syntaxe, "for" est un mot réservé
obj["for"] = "Simon"; // fonctionne très bien

La syntaxe littérale d'objet peut être utilisée pour initialiser un objet dans son intégralité :

var obj = {
    name: "Carotte",
    "for": "Max",
    details: {
        color: "orange",
        size: 12
    }
}

Les accès à des attributs peuvent aussi être chaînés :

> obj.details.color
orange
> obj["details"]["size"]
12

Les tableaux

Les tableaux (Arrays) en JavaScript sont en fait un type spécial d'objets. Ils fonctionnent d'une façon tout à fait similaire aux objets normaux (on ne peut naturellement accéder aux propriétés numériques qu'avec la syntaxe par crochets []) mais ils ont également une propriété magique appelée length. Elle vaut toujours un de plus que le plus grand index dans le tableau.

L'ancienne manière de créer des tableaux est celle-ci :

> var a = new Array();
> a[0] = "chien";
> a[1] = "chat";
> a[2] = "poule";
> a.length
3

Une notation plus pratique est la syntaxe littérale :

> var a = ["chien", "chat", "poule"];
> a.length
3

Laisser une virgule à la fin de la syntaxe littérale produit des résultats incohérents entre les différents navigateurs, donc ne le faites pas.

Notez que array.length n'est pas nécessairement le nombre d'éléments dans le tableau. Observez le code suivant :

> var a = ["chien", "chat", "poule"];
> a[100] = "renard";
> a.length
101

Rappelez-vous : la longueur du tableau est simplement un de plus que l'index le plus élevé.

Si vous interrogez un index de tableau non existant, vous obtenez undefined :

> typeof(a[90])
undefined

Si vous prenez cela en compte, il est possible de parcourir un tableau à l'aide de la boucle suivante :

for (var i = 0; i < a.length; i++) {
    // Faire quelque chose avec a[i]
}

Ce n'est pas la solution la plus performante, parce que l'on examine la propriété length à chaque tour de boucle. Une version améliorée en est :

for (var i = 0, len = a.length; i < len; i++) {
    // Faire quelque chose avec a[i]
}

Mais il est possible d'exprimer cela encore mieux :

for (var i = 0, item; item = a[i]; i++) {
    // Faire quelque chose avec item
}

Ici on définit deux variables. La véracité de l'assignation dans la partie médiane de la boucle for est également vérifiée — si elle est vraie, la boucle continue. Étant donné que i est incrémentée à chaque fois, les éléments du tableau seront assignés à la variable item dans un ordre séquentiel. La boucle s'arrête lorsque la vérification d'un élément renvoie faux (comme c'est le cas d'une valeur undefined).

Notez que cette astuce ne peut être utilisée que pour des tableaux qui ne comprennent pas d'autres valeurs qui pourraient renvoyer une valeur fausse (des tableaux d'objets ou de nœuds DOM par exemple). Si vous parcourez des données numériques parmi lesquelles pourrait se trouver un zéro, ou des chaînes dont l'une pourrait être vide, vous devrez utiliser la variante avec i, len.

Une autre manière de parcourir un tableau est d'utiliser une boucle for...in. Notez que quelqu'un ajoutait d'autres propriétés à Array.prototype, elles seraient également parcourues par cette boucle :

for (var i in a) {
  // faire quelque chose avec a[i]
}

Si vous désirez ajouter un élément à un tableau, la manière la plus sûre est de faire ceci :

a[a.length] = item; // identique à a.push(item);

Étant donné que a.length est toujours un de plus que l'index le plus grand, vous savez sans aucun doute que votre assignation se fait à une position vide en fin de tableau.

Les tableaux ont aussi un certain nombre de méthodes :

a.toString(), a.toLocaleString(), a.concat(item, ..), a.join(sep),
a.pop(), a.push(item, ..), a.reverse(), a.shift(), a.slice(start, end),
a.sort(cmpfn), a.splice(start, delcount, [item]..), a.unshift([item]..)
  • concat renvoie un nouveau tableau auxquels les éléments fournis ont été ajoutés.
  • pop retire et renvoie le dernier élément
  • push ajoute un ou plusieurs éléments à la fin du tableau (comme notre exemple avec ar{{ mediawiki.external('ar.length') }})
  • slice renvoie un sous-tableau
  • sort peut recevoir une fonction de comparaison optionnelle
  • splice permet de modifier un tableau en supprimant une partie et en la remplaçant par d'autres éléments
  • unshift insère des éléments en tête de tableau

Les fonctions

Avec les objets, les fonctions sont les composants de base d'une bonne compréhension de JavaScript. La fonction la plus basique n'a rien de compliqué :

function add(x, y) {
    var total = x + y;
    return total;
}

Ceci représente tout ce qu'il y a à savoir à propos des fonctions basiques. Une fonction JavaScript peut recevoir 0 paramètres nommés ou plus. Son corps peut contenir autant d'instructions que vous le voulez, et permet de déclarer ses propres variables qui sont locales à la fonction. L'instruction return peut être utilisée pour renvoyer une valeur à tout moment, mettant fin à la fonction. Si aucune instruction return n'est utilisée (ou que l'instruction return n'est suivie d'aucune valeur), JavaScript renvoie undefined.

On se rendra compte que les paramètres nommés sont plus des indications qu'autre chose. Il est en effet possible d'appeler une fonction sans lui fournir les paramètres qu'elle attend, auquel cas ils vaudront undefined.

> add()
NaN // Il n'est pas possible d'additionner des variables indéfinies

Il est également possible de fournir plus de paramètres que demandés par la fonction :

> add(2, 3, 4)
5 // les deux premiers sont additionnés ; 4 est ignoré

Par définition les fonctions ont accès à des variables supplémentaires à l'intérieur de leur corps, appelée arguments. Ce sont des objets semblables à un tableau qui conservent toutes les valeurs reçues par la fonction. Réécrivons la fonction add pour recevoir autant de valeurs qu'on veut :

function add() {
    var somme = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        somme += arguments[i];
    }
    return somme;
}

> add(2, 3, 4, 5)
14

Ce n'est cependant pas vraiment plus utile que d'écrire 2 + 3 + 4 + 5. Écrivons plutôt une fonction de calcul de moyenne :

function moyenne() {
    var somme = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        somme += arguments[i];
    }
    return somme / arguments.length;
}
> moyenne(2, 3, 4, 5)
3.5

C'est très pratique, mais on rencontre un nouveau problème. La fonction moyenne() reçoit une liste de valeurs séparées par des virgules, mais si ce qu'on veut c'est trouver la moyenne des valeurs d'un tableau ? On pourrait simplement réécrire la fonction comme ceci :

function moyenneTableau(arr) {
    var somme = 0;
    for (var i = 0, j = arr.length; i < j; i++) {
        somme += arr[i];
    }
    return somme / arr.length;
}
> sommeTableau([2, 3, 4, 5])
3.5

Mais ce serait bien si on pouvait réutiliser la fonction qu'on avait déjà créée. Par chance, JavaScript permet d'appeler une fonction et de lui donner un tableau de paramètres d'une longueur arbitraire, à l'aide de la méthode apply() de tout objet function.

> avg.apply(null, [2, 3, 4, 5])
3.5

Le second paramètre envoyé à apply() est le tableau à utiliser comme paramètres ; nous parlerons du premier plus tard. Cela permet de souligner le fait que les fonctions sont aussi des objets.

JavaScript permet également de créer des fonctions anonymes.

var avg = function() {
    var somme = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        somme += arguments[i];
    }
    return somme / arguments.length;
}

Ceci est sémantiquement équivalent à la forme function moyenne() vue plus haut. C'est extrêmement puissant, car cela permet de mettre une définition de fonction n'importe où, là où on mettrait normalement une expression. C'est la porte ouverte à toutes sortes d'astuces brillantes. Voici par exemple une manière de « cacher » certaines locales variables, comme la visibilité par blocs du C :

> var a = 1;
> var b = 2;
> (function() {
    var b = 3;
    a += b;
})();
> a
4
> b
2

JavaScript permet d'appeler des fonctions récursivement. C'est particulièrement utile lorsqu'on a affaire à des structures en arbre, comme c'est le cas dans le DOM du navigateur.

function countChars(elm) {
    if (elm.nodeType == 3) { // TEXT_NODE
        return elm.nodeValue.length;
    }
    var count = 0;
    for (var i = 0, child; child = elm.childNodes[i]; i++) {
        count += countChars(child);
    }
    return count;
}

Cela permet de mettre le doigt sur un problème potentiel des fonctions anonymes : comment les appellerait-on récursivement si elles n'ont pas de nom ? La réponse se trouve une nouvelle fois dans l'objet arguments, qui non content d'être une liste des paramètres fournit également une propriété appelée arguments.callee. Celle-ci se réfère toujours à la fonction courante, et peut donc être utilisée pour des appels récursifs :

var charsInBody = (function(elm) {
    if (elm.nodeType == 3) { // TEXT_NODE
        return elm.nodeValue.length;
    }
    var count = 0;
    for (var i = 0, child; child = elm.childNodes[i]; i++) {
        count += arguments.callee(child);
    }
    return count;
})(document.body);

Étant donné que arguments.callee est la fonction courante, et que toutes les fonctions sont des objets, vous pouvez utiliser arguments.callee pour enregistrer des informations entre différents appels à la même fonction. Voici une fonction qui se souvient du nombre de fois qu'elle a été appelée :

function counter() {
    if (!arguments.callee.count) {
        arguments.callee.count = 0;
    }
    return arguments.callee.count++;
}

> counter()
0
> counter()
1
> counter()
2

Objets personnalisés

Dans la programmation orientée objet classique, les objets sont des collections de données et de méthodes opérant sur ces données. Imaginons un objet personne avec les champs prénom et nom. Il y a deux manières d'afficher son nom complet : de la façon « prénom nom » ou de la façon « nom, prénom ». À l'aide des fonctions et des objets vus précédemment, voici une manière de le faire :

function makePersonne(prenom, nom) {
    return {
        prenom: prenom,
        nom: nom
    }
}

function personneNomComplet(personne) {
    return personne.prenom + ' ' + personne.nom;
}

function personneNomCompletInverse(personne) {
    return personne.nom + ', ' + personne.prenom;
}

> s = makePersonne("Simon", "Willison");
> personneNomComplet(s)
Simon Willison

> personneNomCompletInverse(s)
Willison, Simon

Ça fonctionne, mais c'est très moche. On va se retrouver avec des dizaines de fonctions dans l'espace de noms global. Ce dont on aurait vraiment besoin c'est d'une manière d'attacher une fonction à un objet. Comme les fonctions sont des objets, c'est facile :

function makePersonne(prenom, nom) {
    return {
        prenom: prenom,
        nom: nom,
        nomComplet: function() {
            return this.prenom + ' ' + this.nom;
        },
        nomCompletInverse: function() {
            return this.nom + ', ' + this.prenom;
        }
    }
}

> s = makePerson("Simon", "Willison")
> s.nomComplet()
Simon Willison

> s.nomCompletInverse()
Willison, Simon

Il y a quelque chose que nous n'avons pas vu jusqu'à présent : le mot-clé this. Utilisé au sein d'une fonction, this réfère à l'objet courant. Ce que cela signifie réellement est spécifié par la manière dont la fonction a été appelée. Si elle a été appelée avec la notation utilisant le point ou les crochets sur un objet, cet objet devient this. Si cette notation n'a pas été utilisée pour l'appel, this réfère à l'objet global. C'est une source fréquente d'erreurs. Par exemple :

> s = makePersonne("Simon", "Willison")
> var nomComplet = s.nomComplet;
> nomComplet()
undefined undefined

Lorsqu'on appelle nomComplet(), this est lié à l'objet global. Comme il n'y a pas de variables globales appelées prenom ou nom, on se retrouve avec undefined pour chacune.

On peut se servir du mot clé this pour améliorer notre fonction makePersonne :

function Personne(prenom, nom) {
    this.prenom = prenom;
    this.nom = nom;
    this.nomComplet = function() {
        return this.prenom + ' ' + this.nom;
    }
    this.nomCompletInverse = function() {
        return this.nom + ', ' + this.prenom;
    }
}
var s = new Personne("Simon", "Willison");

Nous avons utilisé un autre nouveau mot clé : new. new est fortement lié à this. Ce qu'il fait c'est créer un nouvel objet vide, et appeler ensuite la fonction spécifiée, avec this pointant vers ce nouvel objet. Les fonctions prévues pour être appelées par new sont appelées des constructeurs. L'usage courant est de mettre la première lettre de ces fonctions en majuscule pour se souvenir de les appeler avec new.

Nos objets personne s'améliorent, mais il leur reste certaines aspérités pas très esthétiques. Chaque fois que l'on crée une personne, on crée deux nouveaux objets de fonctions en même temps. Est-ce que ce ne serait pas mieux si ce code était partagé ?

function personneNomComplet() {
    return this.prenom + ' ' + this.nom;
}

function personneNomCompletInverse() {
    return this.nom + ', ' + this.prenom;
}

function Personne(prenom, nom) {
    this.prenom = prenom;
    this.nom = nom;
    this.nomComplet = personneNomComplet;
    this.nomCompletInverse = personneNomCompletInverse;
}

C'est mieux : on crée les fonctions une seule fois, et on leur assigne des références au sein du constructeur. Est-ce qu'il est possible de faire encore mieux que ça ? La réponse est oui :

function Personne(prenom, nom) {
    this.prenom = prenom;
    this.nom = nom;
}

Personne.prototype.nomComplet = function() {
    return this.prenom + ' ' + this.nom;
}
Personne.prototype.nomCompletInverse = function() {
    return this.nom + ', ' + this.prenom;
}

Personne.prototype est un objet partagé par toutes les instances de Personne. Il fait partie d'une chaîne de résolution (qui a un nom spécial, la « chaîne de prototypes ») : chaque fois que vous essayez d'accéder à une propriété de Personne qui n'est pas définie, JavaScript va vérifier Personne.prototype pour voir si cette propriété n'existe pas plutôt à cet endroit. Par conséquent, tout ce qui est assigné à Personne.prototype devient disponible à toutes les instances de ce constructeur via l'objet this.

C'est un outil incroyablement puissant. JavaScript vous laisse modifier le prototype de quelque chose à tout moment dans votre programme, ce qui signifie qu'il est possible d'ajouter des méthodes supplémentaires à des objets existants au cours de l'exécution :

> s = new Personne("Simon", "Willison");
> s.prenomEnMajuscules();
TypeError on line 1: s.prenomEnMajuscules is not a function

> Personne.prototype.prenomEnMajuscules = function() {
    return this.prenom.toUpperCase()
}
> s.prenomEnMajuscules()
SIMON

De façon intéressante, il est également possible d'ajouter des choses au prototype d'objets JavaScript prédéfinis. Ajoutons par exemple une méthode à String qui renvoie cette chaîne à l'envers :

> var s = "Simon";
> s.inverse()
TypeError on line 1: s.inverse is not a function

> String.prototype.inverse = function() {
    var r = "";
    for (var i = this.length - 1; i >= 0; i--) {
        r += this[i];
    }
    return r;
}
> s.inverse()
nomiS

Notre nouvelle méthode fonctionne même sur les chaînes littérales !

> "Ceci peut maintenant être inversé".inverse()
ésrevni ertê tnanetniam tuep iceC

Comme mentionné précédemment, le prototype fait partie d'une chaîne. Le début de cette chaîne est Object.prototype, dont toString() fait partie des méthodes. C'est cette méthode qui est appelée quand vous essayez de représenter un objet sous la forme une chaîne. C'est utile pour déboguer nos objets Personne :

> var s = new Personne("Simon", "Willison");
> s
[object Object]

> Personne.prototype.toString = function() {
    return '<Personne : ' + this.fullName() + '>';
}
> s
<Personne : Simon Willison>

Vous vous souvenez de la fonction moyenne.apply() qui avait un premier paramètre défini à null ? Nous pouvons en reparler à présent. Le premier paramètre à apply() est l'objet qui doit être traité comme this. Par exemple, voici une implémentation triviale de new :

function trivialNew(constructor) {
    var o = {}; // Crée un objet
    constructor.apply(o, arguments);
    return o;
}

Ce n'est pas une réplique exacte de new parce qu'elle n'initialise pas la chaîne de prototype. La méthode apply() est difficile à illustrer, ce n'est pas quelque chose qu'on utilise très souvent, mais c'est utile de savoir qu'elle existe.

apply() a une fonction sœur call, qui à nouveau permet de définir à quoi fait référence this, mais reçoit une liste de paramètres plutôt qu'un tableau.

function nomEnMajuscules() {
    return this.nom.toUpperCase();
}
var s = new Personne("Simon", "Willison");
nomEnMajuscules.call(s);
// Est identique à :
s.nomEnMajuscules = nomEnMajuscules;
s.nomEnMajuscules();

Fonctions internes

Les déclarations de fonctions JavaScript peuvent se trouver à l'intérieur d'autres fonctions. Nous avons déjà vu cela une fois, dans l'une des évolutions de la fonction makePerson(). Un détail important concernant les fonctions internes en JavaScript est qu'elles peuvent accéder à des variables de leur fonction parente :

function betterExampleNeeded() {
    var a = 1;
    function oneMoreThanA() {
        return a + 1;
    }
    return oneMoreThanA();
}

Cela peut s'avérer très utile dans l'écriture de code plus facilement maintenable. Si une fonction dépend d'une ou deux autres fonctions qui ne sont utiles à aucun autre endroit de votre code, vous pouvez intégrer ces fonctions utilitaires à la fonction qui sera appelée de l'extérieur. Cela diminue le nombre de fonctions se trouvant dans l'espace global, ce qui est toujours une bonne chose.

C'est également un bon moyen de se préserver de l'attrait trompeur des variables globales. Lorsqu'on écrit du code complexe, il est souvent tentant d'utiliser des variables globales pour partager des valeurs entre différentes fonctions, ce qui mène à du code difficile à maintenir. Les fonctions internes peuvent partager des variables avec leur parent, de sorte que vous pouvez utiliser ce mécanisme pour coupler des fonctions ensemble lorsque cela a un sens, sans pour autant polluer l'espace de noms global. Des « globales locales » si vous voulez. Cette technique doit être utilisée parcimonieusement, mais il est utile de pouvoir le faire.

Fermetures

Cela nous amène à l'une des abstractions les plus spectaculaires que JavaScript a à nous offrir, mais aussi la plus potentiellement déroutante. Que fait ce bout de code ?

function makeAdder(a) {
    return function(b) {
        return a + b;
    }
}
x = makeAdder(5);
y = makeAdder(20);
x(6)
?
y(7)
?

Le nom de la fonction makeAdder devrait vous donner un indice : elle crée de nouveaux additionneurs sous forme de fonctions qui, quand elles sont appelées avec un paramètre, l'ajoutent à celui avec lequel elles ont été créées.

Ce qui se passe ici est sensiblement la même chose qu'avec les fonctions internes dont nous avons parlé précédemment : une fonction définie à l'intérieur d'une autre fonction a accès aux variables de sa fonction extérieure. La seule différence ici est que la fonction extérieure a déjà renvoyé son résultat, et le bon sens semblerait vouloir être que ses variables locales n'existent plus. Mais en fait si, elles existent encore ; autrement les additionneurs présentés ci-dessus ne fonctionneraient pas. Mais ce n'est pas tout, il y a même deux « copies » différentes des variables locales de makeAdder : une dans laquelle a vaut 5 et une autre dans laquelle a vaut 20. Quel est donc le résultat de ces appels de fonction ?

 x(6); // renvoie 11
 y(7); // renvoie 27

Voici ce qui se passe en réalité. Lorsque JavaScript exécute une fonction, un objet de « visibilité » est créé pour conserver les variables locales créées au sein de cette fonction. Il est initialisé avec les variables passées en paramètres à la fonction. Cela ressemble à l'objet global dans lequel toutes les variables et fonctions globales se trouvent, mais avec quelques différences importantes : premièrement, un nouvel objet de visibilité est créé chaque fois qu'une fonction commence à s'exécuter, et deuxièmement, contrairement à l'objet global (qui dans les navigateurs correspond à l'objet window) on ne peut pas directement accéder à ces objets de visibilité depuis le code JavaScript. Il n'existe pas de mécanisme permettant de parcourir les propriétés de l'objet de visibilité courant par exemple.

Donc, quand makeAdder est appelée, un objet de visibilité est créé avec une propriété : a, qui est le paramètre passé à la fonction makeAdder. Celle-ci renvoie alors une fonction nouvellement créée. Normalement, le garbage collector de JavaScript devrait supprimer l'objet de visibilité créé pour makeAdder à ce moment, mais la fonction renvoyée garde une référence vers cet objet de visibilité. Par conséquent, il ne sera pas supprimé par le garbage collector tant qu'il reste des références à l'objet function que makeAdder a renvoyé.

Certains objets de visibilité forment une chaîne appelée la chaîne de visibilité, semblable à la chaîne de prototypes utilisée par le système d'objets de JavaScript.

Ce qu'on appelle une fermeture est la combinaison d'une fonction et de l'objet de visibilité dans lequel elle a été créée.

Les fermetures permettent des enregistrements d'état, et en tant que telles peuvent souvent être utilisées à la place d'objets.

Fuites de mémoire

Un effet de bord indésirable des fermetures est qu'elles rendent trivialement simple la création de fuites mémoire dans Internet Explorer. JavaScript est un langage avec garbage collector - il alloue de la mémoire aux objets au moment de leur création et cette mémoire est libérée par le navigateur lorsque plus aucune référence à un objet ne reste. Les objets fournis par l'environnement hôte sont gérés par cet environnement.

Le navigateur hôte doit gérer un grand nombre d'objets représentant la page HTML affichée, les objets du DOM. C'est à lui de gérer les allocations et la libération de ceux-ci.

Internet Explorer utilise son propre mécanisme de garbage collector pour cela, séparé de celui utilisé par JavaScript. C'est l'interaction entre les deux qui peut provoquer des fuites mémoire.

Une fuite mémoire dans IE se produit chaque fois qu'une référence circulaire est formée entre un objet JavaScript et un objet natif. Imaginons le code suivant :

function fuiteMemoire() {
    var el = document.getElementById('el');
    var o = { 'el': el };
    el.o = o;
}

La référence circulaire formée ci-dessus crée une fuite mémoire ; IE ne libèrera pas la mémoire utilisée par el et o tant que le navigateur n'est pas totalement relancé.

Un cas comme celui exposé ci-dessus passera probablement inaperçu ; les fuites mémoire deviennent seulement un vrai problème dans les applications qui tournent très longtemps ou qui occupent une grande quantité de mémoire à cause de grandes structures de données ou de scénarios de fuites à répétition en boucle.

Les fuites mémoire sont rarement si évidentes ; souvent la structure de données en cause peut être constituée de nombreuses couches de références, ce qui rend la référence circulaire difficile à voir.

Les fermetures rendent très facile la création d'une fuite mémoire sans le vouloir. Examinez par exemple ceci :

function addHandler() {
    var el = document.getElementById('el');
    el.onclick = function() {
        this.style.backgroundColor = 'red';
    }
}

Le code ci-dessus permet à l'élément de s'afficher en rouge lorsqu'on clique dessus. Il crée également un fuite mémoire. Pourquoi ? Parce que la référence à el est prise par inadvertance dans une fermeture créée pour la fonction anonyme interne. Cela crée une référence circulaire entre un objet JavaScript (la fonction) et un objet natif (el).

Il existe plusieurs manières de contourner ce problème. La plus simple est celle-ci :

function addHandler() {
    var el = document.getElementById('el');
    el.onclick = function() {
        this.style.backgroundColor = 'red';
    }
    el = null;
}

Elle fonctionne en cassant la référence circulaire.

Plus étonnant, une des astuces permettant de briser une référence circulaire induite par une fermeture est d'ajouter une autre fermeture :

function addHandler() {
    var clickHandler = function() {
        this.style.backgroundColor = 'red';
    }
    (function() {
        var el = document.getElementById('el');
        el.onclick = clickHandler;
    })();
}

La fonction interne est exécutée directement, et masque son contenu de la fermeture créée avec clickHandler.

Une autre astuce intéressante pour éviter les fuites provoquées par les fermetures est de briser les références circulaires au cours de l'évènement window.onunload. Nombreuses sont les bibliothèques de gestion d'évènements qui le feront à votre place. Remarquez que cela désactive bfcache dans Firefox 1.5, par conséquent vous ne devriez pas mettre en place de gestion pour l'évènement unload dans Firefox, à moins que ce soit nécessaire pour d'autres raisons.

Informations sur le document original

  • Auteur : Simon Willison
  • Date de dernière mise à jour : 7 mars 2006
  • Copyright : © 2006 Simon Willison, fourni sous la licence Creative Commons: Attribute-Sharealike 2.0.
  • Informations complémentaires : Pour plus d'informations à propos de ce tutoriel (et pour des liens vers les slides de la présentation originale), consultez le billet Etech du blog de Simon Willison.

 

 

 

 

 

{{ languages( { "en": "en/A_re-introduction_to_JavaScript", "it": "it/Una_re-introduzione_a_Javascript", "ja": "ja/A_re-introduction_to_JavaScript", "ko": "ko/A_re-introduction_to_JavaScript", "pl": "pl/JavaScript/Na_pocz\u0105tek", "ru": "ru/\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0435_\u0432\u0432\u0435\u0434\u0435\u043d\u0438\u0435_\u0432_JavaScript", "zh-cn": "cn/A_re-introduction_to_JavaScript", "zh-tw": "zh_tw/\u91cd\u65b0\u4ecb\u7d39_JavaScript" } ) }}

Source de la révision

<p>&nbsp;</p>
<h3 id="Introduction" name="Introduction">Introduction</h3>
<p>Pourquoi une réintroduction&nbsp;? Parce que <a href="/fr/JavaScript" title="fr/JavaScript">JavaScript</a> peut raisonnablement se targuer d'être <a class="external" href="http://javascript.crockford.com/javascript.html">le langage de programmation le plus incompris au monde</a>. Bien que souvent raillé comme étant un simple jouet, derrière sa simplicité désarmante se cachent certaines fonctionnalités de langage très puissantes. On a vu au cours de l'année 2005 l'apparition d'un certain nombre d'applications JavaScript de tout premier plan, ce qui montre qu'une connaissance approfondie de cette technologie est une compétence importante pour tout développeur Web.</p>
<p>Il peut être utile de commencer avec une idée de l'histoire de ce langage. JavaScript a été créé en 1995 par Brendan Eich, un ingénieur chez Netscape, et fourni pour la première fois avec Netscape 2 début 1996. Il était au départ censé s'appeler LiveScript, mais a été renommé par une décision marketing néfaste dans le but de capitaliser sur la popularité du langage Java de Sun Microsystems, malgré le fait qu'ils n'aient que très peu en commun. Cela n'a jamais cessé d'être une source de confusion.</p>
<p>Quelques mois plus tard, Microsoft a lancé avec Internet Explorer 3 une version du langage globalement compatible, appelée JScript. Netscape a soumis le langage à l'<a class="external" href="http://www.ecma-international.org/">Ecma International</a>, une organisation de normalisation européenne, ce qui a abouti à la première édition du standard <a href="/fr/ECMAScript" title="fr/ECMAScript">ECMAScript</a> en 1997. Ce standard a reçu une mise à jour importante appelée <a class="external" href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMAScript edition 3</a> en 1999, et n'a plus bougé depuis. La quatrième édition a été abandonnée suite à des différents portants sur la complexité du langage. De nombreuses sections de la quatrième édition ont été utilisées pour servir de fondation à la cinquième édition d'ECMAScript, publiée en décembre 2009.</p>
<p>Cette stabilité est une excellente nouvelle pour les développeurs, parce qu'elle a donné aux différentes implémentations tout le temps nécessaire pour s'y adapter. Je me concentrerai presque exclusivement sur le dialecte de l'édition 3. Pour faciliter la lecture, le terme JavaScript sera cependant utilisé tout au long de cet article.</p>
<p>Contrairement à la plupart des langages de programmation, JavaScript n'a pas de concept d'entrée ou de sortie. Il est conçu pour s'exécuter comme un langage de script dans un environnement hôte, et c'est à cet environnement de fournir des mécanismes de communication avec le monde extérieur. L'environnement hôte le plus commun est un navigateur, mais des interpréteurs JavaScript existent également dans Adobe Acrobat, Photoshop, le moteur de widgets de Yahoo!, et même au sein d'environnements côté serveur.</p>
<h3 id="Aper.C3.A7u" name="Aper.C3.A7u">Aperçu</h3>
<p>JavaScript est un langage dynamique orienté objet ; il dispose de différents typages, opérateurs, objets coeurs et méthodes. Sa syntaxe s'inspire des langages Java et C, donc de nombreuses structures de ces langages s'appliquent également à JavaScript. À la différence de ces langages, JavaScript n'a pas de classes ; au lieu de cela, la fonctionnalité des classes est reprise par les prototypes d'objet. L'autre grande différence tient dans le fait que les fonctions sont des objets, ce qui leur permet de contenir du code executable et d'être transmises comme n'importe quel objet.</p>
<p>Commençons par nous intéresser à la brique de base de tout langage&nbsp;: les types. Les programmes en JavaScript manipulent des valeurs, et ces valeurs appartiennent toutes à un type. Les types JavaScript sont&nbsp;:</p>
<ul>
  <li><a href="/fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Number" title="fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Number">Les nombres (Numbers)</a></li>
  <li><a href="/fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/String" title="fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/String">Les chaînes (Strings)</a></li>
  <li><a href="/fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Boolean" title="fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Boolean">Les booléens (Booleans)</a></li>
  <li><a href="/fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Function" title="fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Function">Les fonctions (Functions)</a></li>
  <li><a href="/fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Object" title="fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Object">Les objets (Objects)</a></li>
</ul>
<p>… oh, et <code>Undefined</code> et <code>Null</code>, qui sont relativement étranges. Et <a href="/fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Array" title="fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Array">les tableaux (Arrays)</a>, qui sont une sorte particulière d'objets. Et les <a href="/fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Date" title="fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Date">Dates</a> et les <a href="/fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/RegExp" title="fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/RegExp">expressions régulières (Regular Expressions)</a>, qui sont des également des objets, pour faire bonne mesure. Et pour être techniquement irréprochable, les fonctions sont aussi une sorte particulère d'objets. De sorte que le diagramme de types ressemble en fait plus à ceci&nbsp;:</p>
<ul>
  <li>Number</li>
  <li>String</li>
  <li>Boolean</li>
  <li>Object
    <ul>
      <li>Function</li>
      <li>Array</li>
      <li>Date</li>
      <li>RegExp</li>
    </ul>
  </li>
  <li>Null</li>
  <li>Undefined</li>
</ul>
<p>Enfin, il y a également quelques types d'<a href="/fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Error" title="fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Error">erreurs</a>. Les choses sont malgré tout beaucoup plus simples si on en reste au premier diagramme.</p>
<h3 id="Les_nombres" name="Les_nombres">Les nombres</h3>
<p>Les nombres en JavaScript sont «&nbsp;des valeurs au format IEEE 754 en double précision 64 bits&nbsp;», d'après la spécification. Les conséquences de ce choix sont intéressantes. Il n'y a par exemple pas de type entier en JavaScript, donc il vous faudra faire preuve d'un petit peu de prudence avec vos opérations arithmétiques si vous avez l'habitude de faire des maths en C ou en Java. Attendez-vous à obtenir des résultats comme&nbsp;:</p>
<pre class="eval">
0.1 + 0.2 = 0.30000000000000004
</pre>
<p>Les <a href="/fr/Référence_de_JavaScript_1.5_Core/Opérateurs/Opérateurs_arithmétiques" title="fr/Référence_de_JavaScript_1.5_Core/Opérateurs/Opérateurs_arithmétiques">opérateurs numériques</a> standards sont gérés, dont l'addition, la soustraction, le modulo (ou reste) arithmétique et ainsi de suite. Il y a également un objet natif qui n'a pas été mentionné jusqu'à présent, appelé <a href="/fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Math" title="fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/Math">Math</a>, pour gérer des fonctions et constantes mathématiques plus avancées&nbsp;:</p>
<pre class="eval">
Math.sin(3.5);
d = Math.PI * r * r;
</pre>
<p>On peut convertir une chaîne en un nombre entier à l'aide de la fonction intégrée <code><a href="/fr/Référence_de_JavaScript_1.5_Core/Fonctions_globales/parseInt" title="fr/Référence_de_JavaScript_1.5_Core/Fonctions_globales/parseInt">parseInt()</a></code>. Elle reçoit la base de conversion comme second paramètre, que vous devriez toujours fournir&nbsp;:</p>
<pre class="eval">
&gt; parseInt("123", 10)
123
&gt; parseInt("010", 10)
10
</pre>
<p>Si vous n'indiquez pas la base, les résultats peuvent être surprenants dans les anciens navigateurs (pré-2013) :</p>
<pre class="eval">
&gt; parseInt("010")
8
</pre>
<p>Cela se produit parce que la fonction <code>parseInt</code> a décidé de traiter la chaîne comme un nombre octal à cause du zéro initial.</p>
<p>Si vous désirez convertir un nombre binaire en un entier, changez simplement la base&nbsp;:</p>
<pre class="eval">
&gt; parseInt("11", 2)
3
</pre>
<p>De la même manière, vous pouvez traiter les nombreux à virgule flottante à l'aide de la fonction intégrée <code><a href="https://developer.mozilla.org/fr/JavaScript/Reference/Global_Objects/parseFloat" title="en/JavaScript/Reference/Global Objects/parseFloat">parseFloat()</a></code>, qui à la différence de sa cousine <a href="https://developer.mozilla.org/fr/JavaScript/Reference/Global_Objects/parseInt" title="en/JavaScript/Reference/Global Objects/parseInt"><code>parseInt()</code></a> utilise toujours la base 10.</p>
<p>Vous pouvez également utiliser l'opétateur unaire <code>+</code> pour convertir des valeurs en nombres :</p>
<pre>
&gt; + "42"
42 
</pre>
<p>Une valeur spéciale appelée <a href="/fr/Référence_de_JavaScript_1.5_Core/Propriétés_globales/NaN" title="fr/Référence_de_JavaScript_1.5_Core/Propriétés_globales/NaN">NaN</a> (qui signifie "Not a Number", soit "pas un nombre") est renvoyée si la chaîne est non numérique&nbsp;:</p>
<pre class="eval">
&gt; parseInt("hello", 10)
NaN
</pre>
<p><code>NaN</code> est toxique&nbsp;: si vous fournissez cette valeur en entrée pour n'importe quelle opération mathématique, le résultat sera également <code>NaN</code>&nbsp;:</p>
<pre class="eval">
&gt; NaN + 5
NaN
</pre>
<p>Vous pouvez la détecter à l'aide de la fonction intégrée <code><a href="/fr/Référence_de_JavaScript_1.5_Core/Fonctions_globales/isNaN" title="fr/Référence_de_JavaScript_1.5_Core/Fonctions_globales/isNaN">isNaN</a></code>&nbsp;:</p>
<pre class="eval">
&gt; isNaN(NaN)
true
</pre>
<p>JavaScript dispose également de valeur spéciales pour <a href="/fr/Référence_de_JavaScript_1.5_Core/Propriétés_globales/Infinity" title="fr/Référence_de_JavaScript_1.5_Core/Propriétés_globales/Infinity">l'infinité</a> (<code>Infinity</code>) et l'infinité négative (<code>-Infinity</code>)&nbsp;:</p>
<pre class="eval">
&gt; 1 / 0
Infinity
&gt; -1 / 0
-Infinity
</pre>
<p>Vous pouvez tester les valeurs <code>Infinity</code>, <code>-Infinity</code> et <code>NaN</code> à l'aide de la fonction intégrée <code><a href="/fr/JavaScript/Reference/Global_Objects/isFinite" title="en/Core_JavaScript_1.5_Reference/Global_Functions/isFinite">isFinite()</a></code> :</p>
<pre class="brush: js">
&gt; isFinite(1/0)
false
&gt; isFinite(-Infinity)
false
&gt; isFinite(NaN)
false
</pre>
<div class="note">
  <strong>Note :</strong> Les fonctions <a href="/fr/JavaScript/Reference/Global_Objects/parseInt" title="en/JavaScript/Reference/Global Objects/parseInt"><code>parseInt()</code></a> et <code><a href="/fr/JavaScript/Reference/Global_Objects/parseFloat" title="en/JavaScript/Reference/Global Objects/parseFloat">parseFloat()</a></code> traitent une chaîne jusqu'à ce qu'elles atteignent un caractère qui n'est pas valide pour le format numérique indiqué, puis renvoie le nombre traité jusqu'à ce point. Cependant, l'opérateur "+" convertit simplement la chaîne à <code>NaN</code> à partir du moment où la chaîne contient le moindre caractère non valide. Essayez simplement de traiter vous même la chaîne "10.2abc" avec chaque méthode dans la console afin de mieux comprendre les différences.</div>
<h3 id="Les_cha.C3.AEnes" name="Les_cha.C3.AEnes">Les chaînes</h3>
<p>Les chaînes en JavaScript sont des séquences de caractères. Plus précisément, elles sont des séquences de <a href="/fr/JavaScript//Guide/Unicode" title="fr/Guide_JavaScript_1.5/Unicode">caractères Unicode</a>, avec chaque caractère représenté par un nombre de 16 bits. Cette nouvelle devrait être bien accueillie par toute personne ayant eu affaire à des problèmes d'internationalisation.</p>
<p>Si vous voulez représenter un seul caractère, il suffit d'utiliser une chaînes de longueur 1.</p>
<p>Pour connaître la longueur d'une chaîne, utilisez sa propriété <code><a href="/fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/String/length" title="fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/String/length">length</a></code>&nbsp;:</p>
<pre class="eval">
&gt; "hello".length
5
</pre>
<p>C'est notre première rencontre avec les objets JavaScript&nbsp;! Est-ce que j'ai précisé que les chaînes étaient des objets également&nbsp;? Elles ont aussi des <a href="/fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/String#M.C3.A9thodes" title="fr/Référence_de_JavaScript_1.5_Core/Objets_globaux/String#M.C3.A9thodes">méthodes</a>&nbsp;:</p>
<pre class="eval">
&gt; "hello".charAt(0)
h
&gt; "hello, world".replace("hello", "goodbye")
goodbye, world
&gt; "hello".toUpperCase()
HELLO
</pre>
<h3 id="Autres_types" name="Autres_types">Autres types</h3>
<p>JavaScript fait la distinction entre <code>null</code>, qui est un objet de type <code>object</code> indiquant une absence délibérée de valeur, et <code>undefined</code> qui est un objet de type <code>undefined</code> indiquant une valeur non initialisée — c'est-à-dire qui a n'a encore été assignée. Nous parlerons des variables plus tard, mais en JavaScript il est possible de déclarer une variable sans lui assigner de valeur. Si vous faites cela, le type de la variable est <code>undefined</code>.</p>
<p>JavaScript dispose d'un type booléen, dont les valeurs possibles sont <code>true</code> (vrai) et <code>false</code> (faux). L'un et l'autre sont des mots clés. Toute valeur peut être convertie en une valeur booléenne selon les règles suivantes&nbsp;:</p>
<ol>
  <li><code>false</code>, <code>0</code>, la chaîne vide (<code>""</code>), <code>NaN</code>, <code>null</code> et <code>undefined</code> deviennent toutes <code>false</code></li>
  <li>toutes les autres valeurs deviennent <code>true</code></li>
</ol>
<p>Cette conversion peut être faite de manière explicite à l'aide de la fonction <code>Boolean()</code>&nbsp;:</p>
<pre class="eval">
&gt; Boolean("");
false
&gt; Boolean(234);
true
</pre>
<p>Cependant, c'est rarement nécessaire, puisque JavaScript effectuera cette conversion silencieusement chaque fois qu'il attend une valeur booléenne, comme dans une instruction <code>if</code> (voir plus bas). Pour cette raison, on parle souvent simplement de valeurs «&nbsp;vraies&nbsp;» et «&nbsp;fausses&nbsp;» pour indiquer des valeurs devenant respectivement <code>true</code> et <code>false</code> lorsqu'elles sont converties en valeurs booléennes.</p>
<p>Les opérations booléennes comme <code>&amp;&amp;</code> (<em>et</em> logique), <code>||</code> (<em>ou</em> logique) et <code>!</code> (<em>non</em> logique) sont également gérées, comme on le verra plus bas.</p>
<h3 id="Les_variables" name="Les_variables">Les variables</h3>
<p>Les nouvelles variables en JavaScript sont déclarées à l'aide du mot clé <code><a href="/fr/Référence_de_JavaScript_1.5_Core/Instructions/var" title="fr/Référence_de_JavaScript_1.5_Core/Instructions/var">var</a></code>&nbsp;:</p>
<pre class="eval">
var a;
var name = "simon";
</pre>
<p>Si vous déclarez une variable sans lui assigner quoi que ce soit, sa valeur est <code>undefined</code>. <span class="comment">should note the absence of block-scoping in JS</span></p>
<h3 id="Les_op.C3.A9rateurs" name="Les_op.C3.A9rateurs">Les opérateurs</h3>
<p>Les opérateurs numériques en JavaScript sont <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code> et <code>%</code> (qui est l'opérateur de reste). Les valeurs sont assignées à l'aide de <code>=</code>, et il existe également des opérateurs d'assignation combinés comme <code>+=</code> et <code>-=</code>. Ils sont équivalents à <code>x = x <em>opérateur</em> y</code>.</p>
<pre class="eval">
x += 5
x = x + 5
</pre>
<p>Vous pouvez utiliser <code>++</code> et <code>--</code> respectivement pour incrémenter et pour décrémenter. Ils peuvent être utilisés comme opérateurs préfixes ou postfixes.</p>
<p>L'<a href="/fr/Référence_de_JavaScript_1.5_Core/Opérateurs/Opérateurs_de_chaînes" title="fr/Référence_de_JavaScript_1.5_Core/Opérateurs/Opérateurs_de_chaînes">opérateur <code>+</code> </a> se charge également de concaténer des chaînes&nbsp;:</p>
<pre class="eval">
&gt; "hello" + " world"
hello world
</pre>
<p>Si vous additionnez une chaîne à un nombre (ou une autre valeur), tout est d'abord converti en une chaîne. Ceci pourrait vous surprendre&nbsp;:</p>
<pre class="eval">
&gt; "3" + 4 + 5
345
&gt; 3 + 4 + "5"
75
</pre>
<p>L'ajout d'une chaîne vide à quelque chose est une manière utile de la convertir en une chaîne.</p>
<p>Les <a href="/fr/Référence_de_JavaScript_1.5_Core/Opérateurs/Opérateurs_de_comparaison" title="fr/Référence_de_JavaScript_1.5_Core/Opérateurs/Opérateurs_de_comparaison">comparaisons</a> en JavaScript se font à l'aide de <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code> et <code>&gt;=</code>. Ceux-ci fonctionnent tant pour les chaînes que pour les nombres. L'égalité est un peu moins évidente. L'opérateur double égal effectue une équivalence si vous lui donnez des types différents, ce qui donne parfois des résultats intéressants&nbsp;:</p>
<pre class="eval">
&gt; "dog" == "dog"
true
&gt; 1 == true
true
</pre>
<p>Pour éviter les calculs d'équivalences de types, utilisez l'opérateur triple égal&nbsp;:</p>
<pre class="eval">
&gt; 1 === true
false
&gt; true === true
true
</pre>
<p>Les opérateurs <code>!=</code> et <code>!==</code> existent également.</p>
<p>JavaScript dispose également d'<a href="/fr/Référence_de_JavaScript_1.5_Core/Opérateurs/Opérateurs_binaires" title="fr/Référence_de_JavaScript_1.5_Core/Opérateurs/Opérateurs_binaires">opérations bit à bit</a>. Si vous en avez besoin, elles sont là.</p>
<h3 id="Les_structures_de_contr.C3.B4le" name="Les_structures_de_contr.C3.B4le">Les structures de contrôle</h3>
<p>JavaScript dispose d'un ensemble de structures de contrôles similaire aux autres langages de la famille du C. Les structures conditionnelles sont présentées avec <code>if</code> et <code>else</code>&nbsp;; lesquels peuvent être chaînés si on le désire&nbsp;:</p>
<pre class="eval">
var name = "des chatons";
if (name == "des chiots") {
  name += "&nbsp;!";
} else if (name == "des chatons") {
  name += "&nbsp;!!";
} else {
  name = "&nbsp;!" + name;
}
name == "des chatons&nbsp;!!"
</pre>
<p>JavaScript dispose également de boucles <code>while</code> et <code>do-while</code>. Les premières sont bonnes pour des boucles basiques&nbsp;; les secondes pour des boucles pour lesquelles vous voulez vous assurer que le corps de la boucle sera exécuté au moins une fois&nbsp;:</p>
<pre class="eval">
while (true) {
  // une boucle infinie&nbsp;!
}

do {
  var input = get_input();
} while (inputIsNotValid(input))
</pre>
<p>Les boucles <code>for</code> en JavaScript sont les mêmes qu'en C et en Java&nbsp;: elles permettent de fournir les informations de contrôle de la boucle en une seule ligne.</p>
<pre class="eval">
for (var i = 0; i &lt; 5; i++) {
  // Sera exécutée cinq fois
}
</pre>
<p>Les opérateurs <code>&amp;&amp;</code> et <code>||</code> utilisent une logique de court-circuit, ce qui signifie qu'ils exécuteront leur second opérande ou non selon la valeur du premier. C'est très utile pour vérifier qu'un objet n'est pas égal à <code>null</code> avant d'essayer d'accéder à ses attributs&nbsp;:</p>
<pre class="eval">
var name = o &amp;&amp; o.getName();
</pre>
<p>Ou pour définir des valeurs par défaut&nbsp;:</p>
<pre class="eval">
var name = otherName || "default";
</pre>
<p>JavaScript propose également un opérateur ternaire pour les assignations conditionnelles en une ligne&nbsp;:</p>
<pre class="eval">
var permis = (age &gt; 18)&nbsp;? "oui"&nbsp;: "non";
</pre>
<p>L'instruction <code>switch</code> peut être utilisée pour différentes branches de code basées sur un nombre ou une chaîne&nbsp;:</p>
<pre class="eval">
switch(action) {
    case 'dessiner':
        dessine();
        break;
    case 'manger':
        mange();
        break;
    default:
        nerienfaire();
}
</pre>
<p>Si vous n'ajoutez pas d'instruction <code>break</code>, l'exécution va se poursuivre au niveau suivant. C'est rarement ce qui est désiré, en fait ça vaut même la peine de préciser dans un commentaire si la poursuite au cas suivant est délibérée pour aider au débogage&nbsp;:</p>
<pre class="eval">
switch(a) {
    case 1: // identique au cas 2
    case 2:
        mange();
        break;
    default:
        nerienfaire();
}
</pre>
<p>La clause <code>default</code> est optionnelle. Vous pouvez placer des expressions à la fois dans la partie <code>switch</code> et dans les cas à gérer si vous voulez&nbsp;; les comparaisons entre les deux se font comme si on avait utilisé l'opérateur <code>===</code>&nbsp;:</p>
<pre class="eval">
switch(1 + 3):
    case 2 + 2:
        yay();
        break;
    default:
        narrivejamais();
}
</pre>
<h3 id="Les_objets" name="Les_objets">Les objets</h3>
<p>Les objets en JavaScript sont simplement des collections de paires nom-valeur. Dans ce sens, ils sont similaires aux&nbsp;:</p>
<ul>
  <li>dictionnaires en Python</li>
  <li>hashs en Perl et Ruby</li>
  <li>tables de hashing en C et C++</li>
  <li>HashMaps en Java</li>
  <li>tableaux associatifs en PHP</li>
</ul>
<p>Le fait que cette structure de données soit si largement utilisée est un témoignage de sa polyvalence. Puisque tout (sauf les types de base) est un objet en JavaScript, tout programme écrit dans ce langage implique naturellement un grand nombre de recherches dans des tables de hashing. C'est une bonne chose que ce soit si rapide&nbsp;!</p>
<p>La partie «&nbsp;nom&nbsp;» est une chaîne JavaScript, tandis que la partie «&nbsp;valeur&nbsp;» peut être n'importe quelle valeur JavaScript, en ce compris d'autres objets. Cela permet de construire des structures de données de n'importe quel niveau de complexité arbitraire.</p>
<p>Il existe deux façons très simples de créer un objet vide&nbsp;:</p>
<pre class="eval">
var obj = new Object();
</pre>
<p>Et&nbsp;:</p>
<pre class="eval">
var obj = {};
</pre>
<p>Ces deux lignes sont sémantiquement équivalentes&nbsp;; la seconde est appelée la syntaxe littérale d'objet, et est beaucoup plus pratique. Cette syntaxe n'existait pas dans les toutes premières version du langage, c'est pourquoi on voit tellement de code utilisant l'ancienne méthode.</p>
<p>Une fois l'objet créé, ses propriétés peuvent à nouveau être consultées de deux manières différentes&nbsp;:</p>
<pre class="eval">
obj.name = "Simon"
var name = obj.name;
</pre>
<p>Et…</p>
<pre class="eval">
obj["name"] = "Simon";
var name = obj["name"];
</pre>
<p>Ces lignes sont également sémantiquement équivalentes. La seconde méthode a l'avantage de fournir le nom de l'objet dans une chaîne, ce qui signifie qu'il peut être calculé au moment de l'exécution. Elle peut également être utilisée pour définir et lire des propriétés dont les noms sont des <a href="/fr/Référence_de_JavaScript_1.5_Core/Mots_réservés" title="fr/Référence_de_JavaScript_1.5_Core/Mots_réservés">mots réservés</a>&nbsp;:</p>
<pre class="eval">
obj.for = "Simon"; // erreur de syntaxe, "for" est un mot réservé
obj["for"] = "Simon"; // fonctionne très bien
</pre>
<p>La syntaxe littérale d'objet peut être utilisée pour initialiser un objet dans son intégralité&nbsp;:</p>
<pre class="eval">
var obj = {
    name: "Carotte",
    "for": "Max",
    details: {
        color: "orange",
        size: 12
    }
}
</pre>
<p>Les accès à des attributs peuvent aussi être chaînés&nbsp;:</p>
<pre class="eval">
&gt; obj.details.color
orange
&gt; obj["details"]["size"]
12
</pre>
<h3 id="Les_tableaux" name="Les_tableaux">Les tableaux</h3>
<p>Les tableaux (Arrays) en JavaScript sont en fait un type spécial d'objets. Ils fonctionnent d'une façon tout à fait similaire aux objets normaux (on ne peut naturellement accéder aux propriétés numériques qu'avec la syntaxe par crochets <code>[]</code>) mais ils ont également une propriété magique appelée <code>length</code>. Elle vaut toujours un de plus que le plus grand index dans le tableau.</p>
<p>L'ancienne manière de créer des tableaux est celle-ci&nbsp;:</p>
<pre class="eval">
&gt; var a = new Array();
&gt; a[0] = "chien";
&gt; a[1] = "chat";
&gt; a[2] = "poule";
&gt; a.length
3
</pre>
<p>Une notation plus pratique est la syntaxe littérale&nbsp;:</p>
<pre class="eval">
&gt; var a = ["chien", "chat", "poule"];
&gt; a.length
3
</pre>
<p>Laisser une virgule à la fin de la syntaxe littérale produit des résultats incohérents entre les différents navigateurs, donc ne le faites pas.</p>
<p>Notez que <code>array.length</code> n'est pas nécessairement le nombre d'éléments dans le tableau. Observez le code suivant&nbsp;:</p>
<pre class="eval">
&gt; var a = ["chien", "chat", "poule"];
&gt; a[100] = "renard";
&gt; a.length
101
</pre>
<p>Rappelez-vous&nbsp;: la longueur du tableau est simplement un de plus que l'index le plus élevé.</p>
<p>Si vous interrogez un index de tableau non existant, vous obtenez <code>undefined</code>&nbsp;:</p>
<pre class="eval">
&gt; typeof(a[90])
undefined
</pre>
<p>Si vous prenez cela en compte, il est possible de parcourir un tableau à l'aide de la boucle suivante&nbsp;:</p>
<pre class="eval">
for (var i = 0; i &lt; a.length; i++) {
    // Faire quelque chose avec a[i]
}
</pre>
<p>Ce n'est pas la solution la plus performante, parce que l'on examine la propriété <code>length</code> à chaque tour de boucle. Une version améliorée en est&nbsp;:</p>
<pre class="eval">
for (var i = 0, len = a.length; i &lt; len; i++) {
    // Faire quelque chose avec a[i]
}
</pre>
<p>Mais il est possible d'exprimer cela encore mieux&nbsp;:</p>
<pre class="eval">
for (var i = 0, item; item = a[i]; i++) {
    // Faire quelque chose avec item
}
</pre>
<p>Ici on définit deux variables. La véracité de l'assignation dans la partie médiane de la boucle <code>for</code> est également vérifiée — si elle est vraie, la boucle continue. Étant donné que <code>i</code> est incrémentée à chaque fois, les éléments du tableau seront assignés à la variable <code>item</code> dans un ordre séquentiel. La boucle s'arrête lorsque la vérification d'un élément renvoie faux (comme c'est le cas d'une valeur <code>undefined</code>).</p>
<p>Notez que cette astuce ne peut être utilisée que pour des tableaux qui ne comprennent pas d'autres valeurs qui pourraient renvoyer une valeur fausse (des tableaux d'objets ou de nœuds <a href="/fr/DOM" title="fr/DOM">DOM</a> par exemple). Si vous parcourez des données numériques parmi lesquelles pourrait se trouver un zéro, ou des chaînes dont l'une pourrait être vide, vous devrez utiliser la variante avec <code>i, len</code>.</p>
<p>Une autre manière de parcourir un tableau est d'utiliser une boucle <code><a href="/fr/Référence_de_JavaScript_1.5_Core/Instructions/for...in" title="fr/Référence_de_JavaScript_1.5_Core/Instructions/for...in">for...in</a></code>. Notez que quelqu'un ajoutait d'autres propriétés à <code>Array.prototype</code>, elles seraient également parcourues par cette boucle&nbsp;:</p>
<pre class="eval">
for (var i in a) {
  // faire quelque chose avec a[i]
}
</pre>
<p>Si vous désirez ajouter un élément à un tableau, la manière la plus sûre est de faire ceci&nbsp;:</p>
<pre class="eval">
a[a.length] = item; // identique à a.push(item);
</pre>
<p>Étant donné que <code>a.length</code> est toujours un de plus que l'index le plus grand, vous savez sans aucun doute que votre assignation se fait à une position vide en fin de tableau.</p>
<p>Les tableaux ont aussi un certain nombre de méthodes&nbsp;:</p>
<pre class="eval">
a.toString(), a.toLocaleString(), a.concat(item, ..), a.join(sep),
a.pop(), a.push(item, ..), a.reverse(), a.shift(), a.slice(start, end),
a.sort(cmpfn), a.splice(start, delcount, [item]..), a.unshift([item]..)
</pre>
<ul>
  <li><code>concat</code> renvoie un nouveau tableau auxquels les éléments fournis ont été ajoutés.</li>
  <li><code>pop</code> retire et renvoie le dernier élément</li>
  <li><code>push</code> ajoute un ou plusieurs éléments à la fin du tableau (comme notre exemple avec <code>ar{{ mediawiki.external('ar.length') }}</code>)</li>
  <li><code>slice</code> renvoie un sous-tableau</li>
  <li><code>sort</code> peut recevoir une fonction de comparaison optionnelle</li>
  <li><code>splice</code> permet de modifier un tableau en supprimant une partie et en la remplaçant par d'autres éléments</li>
  <li><code>unshift</code> insère des éléments en tête de tableau</li>
</ul>
<h3 id="Les_fonctions" name="Les_fonctions">Les fonctions</h3>
<p>Avec les objets, les fonctions sont les composants de base d'une bonne compréhension de JavaScript. La fonction la plus basique n'a rien de compliqué&nbsp;:</p>
<pre class="eval">
function add(x, y) {
    var total = x + y;
    return total;
}
</pre>
<p>Ceci représente tout ce qu'il y a à savoir à propos des fonctions basiques. Une fonction JavaScript peut recevoir 0 paramètres nommés ou plus. Son corps peut contenir autant d'instructions que vous le voulez, et permet de déclarer ses propres variables qui sont locales à la fonction. L'instruction <code>return</code> peut être utilisée pour renvoyer une valeur à tout moment, mettant fin à la fonction. Si aucune instruction <code>return</code> n'est utilisée (ou que l'instruction <code>return</code> n'est suivie d'aucune valeur), JavaScript renvoie <code>undefined</code>.</p>
<p>On se rendra compte que les paramètres nommés sont plus des indications qu'autre chose. Il est en effet possible d'appeler une fonction sans lui fournir les paramètres qu'elle attend, auquel cas ils vaudront <code>undefined</code>.</p>
<pre class="eval">
&gt; add()
NaN // Il n'est pas possible d'additionner des variables indéfinies
</pre>
<p>Il est également possible de fournir plus de paramètres que demandés par la fonction&nbsp;:</p>
<pre class="eval">
&gt; add(2, 3, 4)
5 // les deux premiers sont additionnés&nbsp;; 4 est ignoré
</pre>
<p>Par définition les fonctions ont accès à des variables supplémentaires à l'intérieur de leur corps, appelée <a href="/fr/Référence_de_JavaScript_1.5_Core/Fonctions/arguments" title="fr/Référence_de_JavaScript_1.5_Core/Fonctions/arguments"><code>arguments</code></a>. Ce sont des objets semblables à un tableau qui conservent toutes les valeurs reçues par la fonction. Réécrivons la fonction add pour recevoir autant de valeurs qu'on veut&nbsp;:</p>
<pre class="eval">
function add() {
    var somme = 0;
    for (var i = 0, j = arguments.length; i &lt; j; i++) {
        somme += arguments[i];
    }
    return somme;
}

&gt; add(2, 3, 4, 5)
14
</pre>
<p>Ce n'est cependant pas vraiment plus utile que d'écrire <code>2 + 3 + 4 + 5</code>. Écrivons plutôt une fonction de calcul de moyenne&nbsp;:</p>
<pre class="eval">
function moyenne() {
    var somme = 0;
    for (var i = 0, j = arguments.length; i &lt; j; i++) {
        somme += arguments[i];
    }
    return somme / arguments.length;
}
&gt; moyenne(2, 3, 4, 5)
3.5
</pre>
<p>C'est très pratique, mais on rencontre un nouveau problème. La fonction <code>moyenne()</code> reçoit une liste de valeurs séparées par des virgules, mais si ce qu'on veut c'est trouver la moyenne des valeurs d'un tableau&nbsp;? On pourrait simplement réécrire la fonction comme ceci&nbsp;:</p>
<pre class="eval">
function moyenneTableau(arr) {
    var somme = 0;
    for (var i = 0, j = arr.length; i &lt; j; i++) {
        somme += arr[i];
    }
    return somme / arr.length;
}
&gt; sommeTableau([2, 3, 4, 5])
3.5
</pre>
<p>Mais ce serait bien si on pouvait réutiliser la fonction qu'on avait déjà créée. Par chance, JavaScript permet d'appeler une fonction et de lui donner un tableau de paramètres d'une longueur arbitraire, à l'aide de la méthode <a href="/fr/Référence_de_JavaScript_1.5_Core/Fonctions/apply" title="fr/Référence_de_JavaScript_1.5_Core/Fonctions/apply"><code>apply()</code></a> de tout objet function.</p>
<pre class="eval">
&gt; avg.apply(null, [2, 3, 4, 5])
3.5
</pre>
<p>Le second paramètre envoyé à <code>apply()</code> est le tableau à utiliser comme paramètres&nbsp;; nous parlerons du premier plus tard. Cela permet de souligner le fait que les fonctions sont aussi des objets.</p>
<p>JavaScript permet également de créer des fonctions anonymes.</p>
<pre class="eval">
var avg = function() {
    var somme = 0;
    for (var i = 0, j = arguments.length; i &lt; j; i++) {
        somme += arguments[i];
    }
    return somme / arguments.length;
}
</pre>
<p>Ceci est sémantiquement équivalent à la forme <code>function moyenne()</code> vue plus haut. C'est extrêmement puissant, car cela permet de mettre une définition de fonction n'importe où, là où on mettrait normalement une expression. C'est la porte ouverte à toutes sortes d'astuces brillantes. Voici par exemple une manière de «&nbsp;cacher&nbsp;» certaines locales variables, comme la visibilité par blocs du C&nbsp;:</p>
<pre class="eval">
&gt; var a = 1;
&gt; var b = 2;
&gt; (function() {
    var b = 3;
    a += b;
})();
&gt; a
4
&gt; b
2
</pre>
<p>JavaScript permet d'appeler des fonctions récursivement. C'est particulièrement utile lorsqu'on a affaire à des structures en arbre, comme c'est le cas dans le <a href="/fr/DOM" title="fr/DOM">DOM</a> du navigateur.</p>
<pre class="eval">
function countChars(elm) {
    if (elm.nodeType == 3) { // TEXT_NODE
        return elm.nodeValue.length;
    }
    var count = 0;
    for (var i = 0, child; child = elm.childNodes[i]; i++) {
        count += countChars(child);
    }
    return count;
}
</pre>
<p>Cela permet de mettre le doigt sur un problème potentiel des fonctions anonymes&nbsp;: comment les appellerait-on récursivement si elles n'ont pas de nom&nbsp;? La réponse se trouve une nouvelle fois dans l'objet <code>arguments</code>, qui non content d'être une liste des paramètres fournit également une propriété appelée <code>arguments.callee</code>. Celle-ci se réfère toujours à la fonction courante, et peut donc être utilisée pour des appels récursifs&nbsp;:</p>
<pre class="eval">
var charsInBody = (function(elm) {
    if (elm.nodeType == 3) { // TEXT_NODE
        return elm.nodeValue.length;
    }
    var count = 0;
    for (var i = 0, child; child = elm.childNodes[i]; i++) {
        count += arguments.callee(child);
    }
    return count;
})(document.body);
</pre>
<p>Étant donné que <code>arguments.callee</code> est la fonction courante, et que toutes les fonctions sont des objets, vous pouvez utiliser <code>arguments.callee</code> pour enregistrer des informations entre différents appels à la même fonction. Voici une fonction qui se souvient du nombre de fois qu'elle a été appelée&nbsp;:</p>
<pre class="eval">
function counter() {
    if (!arguments.callee.count) {
        arguments.callee.count = 0;
    }
    return arguments.callee.count++;
}

&gt; counter()
0
&gt; counter()
1
&gt; counter()
2
</pre>
<h3 id="Objets_personnalis.C3.A9s" name="Objets_personnalis.C3.A9s">Objets personnalisés</h3>
<p>Dans la programmation orientée objet classique, les objets sont des collections de données et de méthodes opérant sur ces données. Imaginons un objet personne avec les champs prénom et nom. Il y a deux manières d'afficher son nom complet&nbsp;: de la façon «&nbsp;prénom nom&nbsp;» ou de la façon «&nbsp;nom, prénom&nbsp;». À l'aide des fonctions et des objets vus précédemment, voici une manière de le faire&nbsp;:</p>
<pre class="eval">
function makePersonne(prenom, nom) {
    return {
        prenom: prenom,
        nom: nom
    }
}

function personneNomComplet(personne) {
    return personne.prenom + ' ' + personne.nom;
}

function personneNomCompletInverse(personne) {
    return personne.nom + ', ' + personne.prenom;
}

&gt; s = makePersonne("Simon", "Willison");
&gt; personneNomComplet(s)
Simon Willison

&gt; personneNomCompletInverse(s)
Willison, Simon
</pre>
<p>Ça fonctionne, mais c'est très moche. On va se retrouver avec des dizaines de fonctions dans l'espace de noms global. Ce dont on aurait vraiment besoin c'est d'une manière d'attacher une fonction à un objet. Comme les fonctions sont des objets, c'est facile&nbsp;:</p>
<pre class="eval">
function makePersonne(prenom, nom) {
    return {
        prenom: prenom,
        nom: nom,
        nomComplet: function() {
            return this.prenom + ' ' + this.nom;
        },
        nomCompletInverse: function() {
            return this.nom + ', ' + this.prenom;
        }
    }
}

&gt; s = makePerson("Simon", "Willison")
&gt; s.nomComplet()
Simon Willison

&gt; s.nomCompletInverse()
Willison, Simon
</pre>
<p>Il y a quelque chose que nous n'avons pas vu jusqu'à présent&nbsp;: le mot-clé <code><a href="/fr/Référence_JavaScript_1.5_Core/Opérateurs/Opérateurs_spéciaux/L'opérateur_this" title="fr/Référence_JavaScript_1.5_Core/Opérateurs/Opérateurs_spéciaux/L'opérateur_this">this</a></code>. Utilisé au sein d'une fonction, <code>this</code> réfère à l'objet courant. Ce que cela signifie réellement est spécifié par la manière dont la fonction a été appelée. Si elle a été appelée avec <a href="/fr/Référence_JavaScript_1.5_Core/Opérateurs/Opérateurs_membres" title="fr/Référence_JavaScript_1.5_Core/Opérateurs/Opérateurs_membres">la notation utilisant le point ou les crochets</a> sur un objet, cet objet devient <code>this</code>. Si cette notation n'a pas été utilisée pour l'appel, <code>this</code> réfère à l'objet global. C'est une source fréquente d'erreurs. Par exemple&nbsp;:</p>
<pre class="eval">
&gt; s = makePersonne("Simon", "Willison")
&gt; var nomComplet = s.nomComplet;
&gt; nomComplet()
undefined undefined
</pre>
<p>Lorsqu'on appelle <code>nomComplet()</code>, <code>this</code> est lié à l'objet global. Comme il n'y a pas de variables globales appelées <code>prenom</code> ou <code>nom</code>, on se retrouve avec <code>undefined</code> pour chacune.</p>
<p>On peut se servir du mot clé <code>this</code> pour améliorer notre fonction <code>makePersonne</code>&nbsp;:</p>
<pre class="eval">
function Personne(prenom, nom) {
    this.prenom = prenom;
    this.nom = nom;
    this.nomComplet = function() {
        return this.prenom + ' ' + this.nom;
    }
    this.nomCompletInverse = function() {
        return this.nom + ', ' + this.prenom;
    }
}
var s = new Personne("Simon", "Willison");
</pre>
<p>Nous avons utilisé un autre nouveau mot clé&nbsp;: <code><a href="/fr/Référence_JavaScript_1.5_Core/Opérateurs/Opérateurs_spéciaux/L'opérateur_new" title="fr/Référence_JavaScript_1.5_Core/Opérateurs/Opérateurs_spéciaux/L'opérateur_new">new</a></code>. <code>new</code> est fortement lié à <code>this</code>. Ce qu'il fait c'est créer un nouvel objet vide, et appeler ensuite la fonction spécifiée, avec <code>this</code> pointant vers ce nouvel objet. Les fonctions prévues pour être appelées par <code>new</code> sont appelées des constructeurs. L'usage courant est de mettre la première lettre de ces fonctions en majuscule pour se souvenir de les appeler avec <code>new</code>.</p>
<p>Nos objets personne s'améliorent, mais il leur reste certaines aspérités pas très esthétiques. Chaque fois que l'on crée une personne, on crée deux nouveaux objets de fonctions en même temps. Est-ce que ce ne serait pas mieux si ce code était partagé&nbsp;?</p>
<pre class="eval">
function personneNomComplet() {
    return this.prenom + ' ' + this.nom;
}

function personneNomCompletInverse() {
    return this.nom + ', ' + this.prenom;
}

function Personne(prenom, nom) {
    this.prenom = prenom;
    this.nom = nom;
    this.nomComplet = personneNomComplet;
    this.nomCompletInverse = personneNomCompletInverse;
}
</pre>
<p>C'est mieux&nbsp;: on crée les fonctions une seule fois, et on leur assigne des références au sein du constructeur. Est-ce qu'il est possible de faire encore mieux que ça&nbsp;? La réponse est oui&nbsp;:</p>
<pre class="eval">
function Personne(prenom, nom) {
    this.prenom = prenom;
    this.nom = nom;
}

Personne.prototype.nomComplet = function() {
    return this.prenom + ' ' + this.nom;
}
Personne.prototype.nomCompletInverse = function() {
    return this.nom + ', ' + this.prenom;
}
</pre>
<p><code>Personne.prototype</code> est un objet partagé par toutes les instances de <code>Personne</code>. Il fait partie d'une chaîne de résolution (qui a un nom spécial, la «&nbsp;chaîne de prototypes&nbsp;»)&nbsp;: chaque fois que vous essayez d'accéder à une propriété de <code>Personne</code> qui n'est pas définie, JavaScript va vérifier <code>Personne.prototype</code> pour voir si cette propriété n'existe pas plutôt à cet endroit. Par conséquent, tout ce qui est assigné à <code>Personne.prototype</code> devient disponible à toutes les instances de ce constructeur via l'objet <code>this</code>.</p>
<p>C'est un outil incroyablement puissant. JavaScript vous laisse modifier le prototype de quelque chose à tout moment dans votre programme, ce qui signifie qu'il est possible d'ajouter des méthodes supplémentaires à des objets existants au cours de l'exécution&nbsp;:</p>
<pre class="eval">
&gt; s = new Personne("Simon", "Willison");
&gt; s.prenomEnMajuscules();
TypeError on line 1: s.prenomEnMajuscules is not a function

&gt; Personne.prototype.prenomEnMajuscules = function() {
    return this.prenom.toUpperCase()
}
&gt; s.prenomEnMajuscules()
SIMON
</pre>
<p>De façon intéressante, il est également possible d'ajouter des choses au prototype d'objets JavaScript prédéfinis. Ajoutons par exemple une méthode à <code>String</code> qui renvoie cette chaîne à l'envers&nbsp;:</p>
<pre class="eval">
&gt; var s = "Simon";
&gt; s.inverse()
TypeError on line 1: s.inverse is not a function

&gt; String.prototype.inverse = function() {
    var r = "";
    for (var i = this.length - 1; i &gt;= 0; i--) {
        r += this[i];
    }
    return r;
}
&gt; s.inverse()
nomiS
</pre>
<p>Notre nouvelle méthode fonctionne même sur les chaînes littérales&nbsp;!</p>
<pre class="eval">
&gt; "Ceci peut maintenant être inversé".inverse()
ésrevni ertê tnanetniam tuep iceC
</pre>
<p>Comme mentionné précédemment, le prototype fait partie d'une chaîne. Le début de cette chaîne est <code>Object.prototype</code>, dont <code>toString()</code> fait partie des méthodes. C'est cette méthode qui est appelée quand vous essayez de représenter un objet sous la forme une chaîne. C'est utile pour déboguer nos objets <code>Personne</code>&nbsp;:</p>
<pre class="eval">
&gt; var s = new Personne("Simon", "Willison");
&gt; s
[object Object]

&gt; Personne.prototype.toString = function() {
    return '&lt;Personne&nbsp;: ' + this.fullName() + '&gt;';
}
&gt; s
&lt;Personne&nbsp;: Simon Willison&gt;
</pre>
<p>Vous vous souvenez de la fonction <code>moyenne.apply()</code> qui avait un premier paramètre défini à <code>null</code>&nbsp;? Nous pouvons en reparler à présent. Le premier paramètre à <code>apply()</code> est l'objet qui doit être traité comme <code>this</code>. Par exemple, voici une implémentation triviale de <code>new</code>&nbsp;:</p>
<pre class="eval">
function trivialNew(constructor) {
    var o = {}; // Crée un objet
    constructor.apply(o, arguments);
    return o;
}
</pre>
<p>Ce n'est pas une réplique exacte de <code>new</code> parce qu'elle n'initialise pas la chaîne de prototype. La méthode <code>apply()</code> est difficile à illustrer, ce n'est pas quelque chose qu'on utilise très souvent, mais c'est utile de savoir qu'elle existe.</p>
<p><code>apply()</code> a une fonction sœur <a href="/fr/Référence_JavaScript_1.5_Core/Objets_globaux/Function/call" title="fr/Référence_JavaScript_1.5_Core/Objets_globaux/Function/call"><code>call</code></a>, qui à nouveau permet de définir à quoi fait référence <code>this</code>, mais reçoit une liste de paramètres plutôt qu'un tableau.</p>
<pre class="eval">
function nomEnMajuscules() {
    return this.nom.toUpperCase();
}
var s = new Personne("Simon", "Willison");
nomEnMajuscules.call(s);
// Est identique à&nbsp;:
s.nomEnMajuscules = nomEnMajuscules;
s.nomEnMajuscules();
</pre>
<h3 id="Fonctions_internes" name="Fonctions_internes">Fonctions internes</h3>
<p>Les déclarations de fonctions JavaScript peuvent se trouver à l'intérieur d'autres fonctions. Nous avons déjà vu cela une fois, dans l'une des évolutions de la fonction <code>makePerson()</code>. Un détail important concernant les fonctions internes en JavaScript est qu'elles peuvent accéder à des variables de leur fonction parente&nbsp;:</p>
<pre class="eval">
function betterExampleNeeded() {
    var a = 1;
    function oneMoreThanA() {
        return a + 1;
    }
    return oneMoreThanA();
}
</pre>
<p>Cela peut s'avérer très utile dans l'écriture de code plus facilement maintenable. Si une fonction dépend d'une ou deux autres fonctions qui ne sont utiles à aucun autre endroit de votre code, vous pouvez intégrer ces fonctions utilitaires à la fonction qui sera appelée de l'extérieur. Cela diminue le nombre de fonctions se trouvant dans l'espace global, ce qui est toujours une bonne chose.</p>
<p>C'est également un bon moyen de se préserver de l'attrait trompeur des variables globales. Lorsqu'on écrit du code complexe, il est souvent tentant d'utiliser des variables globales pour partager des valeurs entre différentes fonctions, ce qui mène à du code difficile à maintenir. Les fonctions internes peuvent partager des variables avec leur parent, de sorte que vous pouvez utiliser ce mécanisme pour coupler des fonctions ensemble lorsque cela a un sens, sans pour autant polluer l'espace de noms global. Des «&nbsp;globales locales&nbsp;» si vous voulez. Cette technique doit être utilisée parcimonieusement, mais il est utile de pouvoir le faire.</p>
<h3 id="Fermetures" name="Fermetures">Fermetures</h3>
<p>Cela nous amène à l'une des abstractions les plus spectaculaires que JavaScript a à nous offrir, mais aussi la plus potentiellement déroutante. Que fait ce bout de code&nbsp;?</p>
<pre class="eval">
function makeAdder(a) {
    return function(b) {
        return a + b;
    }
}
x = makeAdder(5);
y = makeAdder(20);
x(6)
?
y(7)
?
</pre>
<p>Le nom de la fonction <code>makeAdder</code> devrait vous donner un indice&nbsp;: elle crée de nouveaux additionneurs sous forme de fonctions qui, quand elles sont appelées avec un paramètre, l'ajoutent à celui avec lequel elles ont été créées.</p>
<p>Ce qui se passe ici est sensiblement la même chose qu'avec les fonctions internes dont nous avons parlé précédemment&nbsp;: une fonction définie à l'intérieur d'une autre fonction a accès aux variables de sa fonction extérieure. La seule différence ici est que la fonction extérieure a déjà renvoyé son résultat, et le bon sens semblerait vouloir être que ses variables locales n'existent plus. Mais <em>en fait si</em>, elles existent encore&nbsp;; autrement les additionneurs présentés ci-dessus ne fonctionneraient pas. Mais ce n'est pas tout, il y a même deux «&nbsp;copies&nbsp;» différentes des variables locales de <code>makeAdder</code>&nbsp;: une dans laquelle <code>a</code> vaut 5 et une autre dans laquelle <code>a</code> vaut 20. Quel est donc le résultat de ces appels de fonction&nbsp;?</p>
<pre class="eval">
 x(6); // renvoie 11
 y(7); // renvoie 27
</pre>
<p>Voici ce qui se passe en réalité. Lorsque JavaScript exécute une fonction, un objet de «&nbsp;visibilité&nbsp;» est créé pour conserver les variables locales créées au sein de cette fonction. Il est initialisé avec les variables passées en paramètres à la fonction. Cela ressemble à l'objet global dans lequel toutes les variables et fonctions globales se trouvent, mais avec quelques différences importantes&nbsp;: premièrement, un nouvel objet de visibilité est créé chaque fois qu'une fonction commence à s'exécuter, et deuxièmement, contrairement à l'objet global (qui dans les navigateurs correspond à l'objet <code>window</code>) on ne peut pas directement accéder à ces objets de visibilité depuis le code JavaScript. Il n'existe pas de mécanisme permettant de parcourir les propriétés de l'objet de visibilité courant par exemple.</p>
<p>Donc, quand <code>makeAdder</code> est appelée, un objet de visibilité est créé avec une propriété&nbsp;: <code>a</code>, qui est le paramètre passé à la fonction <code>makeAdder</code>. Celle-ci renvoie alors une fonction nouvellement créée. Normalement, le garbage collector de JavaScript devrait supprimer l'objet de visibilité créé pour <code>makeAdder</code> à ce moment, mais la fonction renvoyée garde une référence vers cet objet de visibilité. Par conséquent, il ne sera pas supprimé par le garbage collector tant qu'il reste des références à l'objet <code>function</code> que <code>makeAdder</code> a renvoyé.</p>
<p>Certains objets de visibilité forment une chaîne appelée la chaîne de visibilité, semblable à la chaîne de prototypes utilisée par le système d'objets de JavaScript.</p>
<p>Ce qu'on appelle une fermeture est la combinaison d'une fonction et de l'objet de visibilité dans lequel elle a été créée.</p>
<p>Les fermetures permettent des enregistrements d'état, et en tant que telles peuvent souvent être utilisées à la place d'objets.</p>
<h3 id="Fuites_de_m.C3.A9moire" name="Fuites_de_m.C3.A9moire">Fuites de mémoire</h3>
<p>Un effet de bord indésirable des fermetures est qu'elles rendent trivialement simple la création de fuites mémoire dans Internet Explorer. JavaScript est un langage avec garbage collector - il alloue de la mémoire aux objets au moment de leur création et cette mémoire est libérée par le navigateur lorsque plus aucune référence à un objet ne reste. Les objets fournis par l'environnement hôte sont gérés par cet environnement.</p>
<p>Le navigateur hôte doit gérer un grand nombre d'objets représentant la page HTML affichée, les objets du <a href="/fr/DOM" title="fr/DOM">DOM</a>. C'est à lui de gérer les allocations et la libération de ceux-ci.</p>
<p>Internet Explorer utilise son propre mécanisme de garbage collector pour cela, séparé de celui utilisé par JavaScript. C'est l'interaction entre les deux qui peut provoquer des fuites mémoire.</p>
<p>Une fuite mémoire dans IE se produit chaque fois qu'une référence circulaire est formée entre un objet JavaScript et un objet natif. Imaginons le code suivant&nbsp;:</p>
<pre class="eval">
function fuiteMemoire() {
    var el = document.getElementById('el');
    var o = { 'el': el };
    el.o = o;
}
</pre>
<p>La référence circulaire formée ci-dessus crée une fuite mémoire&nbsp;; IE ne libèrera pas la mémoire utilisée par <code>el</code> et <code>o</code> tant que le navigateur n'est pas totalement relancé.</p>
<p>Un cas comme celui exposé ci-dessus passera probablement inaperçu&nbsp;; les fuites mémoire deviennent seulement un vrai problème dans les applications qui tournent très longtemps ou qui occupent une grande quantité de mémoire à cause de grandes structures de données ou de scénarios de fuites à répétition en boucle.</p>
<p>Les fuites mémoire sont rarement si évidentes&nbsp;; souvent la structure de données en cause peut être constituée de nombreuses couches de références, ce qui rend la référence circulaire difficile à voir.</p>
<p>Les fermetures rendent très facile la création d'une fuite mémoire sans le vouloir. Examinez par exemple ceci&nbsp;:</p>
<pre class="eval">
function addHandler() {
    var el = document.getElementById('el');
    el.onclick = function() {
        this.style.backgroundColor = 'red';
    }
}
</pre>
<p>Le code ci-dessus permet à l'élément de s'afficher en rouge lorsqu'on clique dessus. Il crée également un fuite mémoire. Pourquoi&nbsp;? Parce que la référence à <code>el</code> est prise par inadvertance dans une fermeture créée pour la fonction anonyme interne. Cela crée une référence circulaire entre un objet JavaScript (la fonction) et un objet natif (<code>el</code>).</p>
<p>Il existe plusieurs manières de contourner ce problème. La plus simple est celle-ci&nbsp;:</p>
<pre class="eval">
function addHandler() {
    var el = document.getElementById('el');
    el.onclick = function() {
        this.style.backgroundColor = 'red';
    }
    el = null;
}
</pre>
<p>Elle fonctionne en cassant la référence circulaire.</p>
<p>Plus étonnant, une des astuces permettant de briser une référence circulaire induite par une fermeture est d'ajouter une autre fermeture&nbsp;:</p>
<pre class="eval">
function addHandler() {
    var clickHandler = function() {
        this.style.backgroundColor = 'red';
    }
    (function() {
        var el = document.getElementById('el');
        el.onclick = clickHandler;
    })();
}
</pre>
<p>La fonction interne est exécutée directement, et masque son contenu de la fermeture créée avec <code>clickHandler</code>.</p>
<p>Une autre astuce intéressante pour éviter les fuites provoquées par les fermetures est de briser les références circulaires au cours de l'évènement <code>window.onunload</code>. Nombreuses sont les bibliothèques de gestion d'évènements qui le feront à votre place. Remarquez que cela désactive <a href="/fr/Utilisation_du_cache_de_Firefox_1.5" title="fr/Utilisation_du_cache_de_Firefox_1.5">bfcache dans Firefox 1.5</a>, par conséquent vous ne devriez pas mettre en place de gestion pour l'évènement <code>unload</code> dans Firefox, à moins que ce soit nécessaire pour d'autres raisons.</p>
<div class="originaldocinfo">
  <h3 id="Informations_sur_le_document_original" name="Informations_sur_le_document_original">Informations sur le document original</h3>
  <ul>
    <li>Auteur&nbsp;: <a class="external" href="http://simon.incutio.com/">Simon Willison</a></li>
    <li>Date de dernière mise à jour&nbsp;: 7 mars 2006</li>
    <li>Copyright&nbsp;: © 2006 Simon Willison, fourni sous la licence Creative Commons: Attribute-Sharealike 2.0.</li>
    <li>Informations complémentaires&nbsp;: Pour plus d'informations à propos de ce tutoriel (et pour des liens vers les slides de la présentation originale), consultez le <a class="external" href="http://simon.incutio.com/archive/2006/03/07/etech">billet Etech du blog de Simon Willison</a>.</li>
  </ul>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>{{ languages( { "en": "en/A_re-introduction_to_JavaScript", "it": "it/Una_re-introduzione_a_Javascript", "ja": "ja/A_re-introduction_to_JavaScript", "ko": "ko/A_re-introduction_to_JavaScript", "pl": "pl/JavaScript/Na_pocz\u0105tek", "ru": "ru/\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0435_\u0432\u0432\u0435\u0434\u0435\u043d\u0438\u0435_\u0432_JavaScript", "zh-cn": "cn/A_re-introduction_to_JavaScript", "zh-tw": "zh_tw/\u91cd\u65b0\u4ecb\u7d39_JavaScript" } ) }}</p>
Revenir à cette révision