Les ressources ont été chargées... Je charge...

4.1 Début rapide du langage JavaScript

Auteur:La bonté, Créé: 2019-04-26 11:46:12, mis à jour: 2019-04-27 11:53:43

Retour sur les faits

Cette section donne un petit aperçu de JavaScript pour vous aider à comprendre pourquoi c'est comme ça.

JavaScript contre ECMAScript

ECMAScript est le nom officiel de JavaScript. Un nouveau nom est devenu nécessaire car il existe une marque déposée sur JavaScript (détenue à l'origine par Sun, maintenant par Oracle).

  • JavaScript signifie le langage de programmation.
  • ECMAScript est le nom utilisé par la spécification du langage. Par conséquent, chaque fois que les gens se réfèrent à des versions du langage, ils disent ECMAScript.

Influences et nature du langage

Le créateur de JavaScript, Brendan Eich, n'a pas eu d'autre choix que de créer le langage très rapidement (ou d'autres technologies pires auraient été adoptées par Netscape). Il a emprunté à plusieurs langages de programmation: Java (syntaxe, valeurs primitives par rapport aux objets), Scheme et AWK (fonctions de première classe), Self (héritage prototypique) et Perl et Python (chaînes de caractères, tableaux et expressions régulières).

JavaScript n'avait pas de traitement d'exception jusqu'à ECMAScript 3, ce qui explique pourquoi le langage convertit si souvent automatiquement des valeurs et échoue si souvent silencieusement: il ne pouvait pas lancer d'exceptions au départ.

D'une part, JavaScript a des bizarreries et manque de fonctionnalités (variables à champ de blocs, modules, prise en charge des sous-classes, etc.). D'autre part, il a plusieurs fonctionnalités puissantes qui vous permettent de contourner ces problèmes. Dans d'autres langages, vous apprenez les fonctionnalités du langage. Dans JavaScript, vous apprenez souvent des modèles à la place.

Compte tenu de ses influences, il n'est pas surprenant que JavaScript permette un style de programmation qui est un mélange de programmation fonctionnelle (fonctions d'ordre supérieur; carte intégrée, réduire, etc.) et de programmation orientée objet (objets, héritage).

Syntaxe

Cette section explique les principes syntaxiques de base de JavaScript.

Un aperçu de la syntaxe

Quelques exemples de syntaxe:

// Two slashes start single-line comments

var x;  // declaring a variable

x = 3 + y;  // assigning a value to the variable `x`

foo(x, y);  // calling function `foo` with parameters `x` and `y`
obj.bar(3);  // calling method `bar` of object `obj`

// A conditional statement
if (x === 0) {  // Is `x` equal to zero?
    x = 123;
}

// Defining function `baz` with parameters `a` and `b`
function baz(a, b) {
    return a + b;
}

Notez les deux utilisations différentes du signe égal:

  • Un seul signe égal (=) est utilisé pour attribuer une valeur à une variable.
  • Un signe triple égal (===) est utilisé pour comparer deux valeurs (voir Opérateurs d'égalité).

Les déclarations contre les expressions

Pour comprendre la syntaxe de JavaScript, vous devez savoir qu'il a deux grandes catégories syntaxiques: les déclarations et les expressions:

  • Les instructions do things. Un programme est une séquence d'instructions. Voici un exemple d'instruction, qui déclare (crée) une variable foo:
var foo;
  • Les expressions produisent des valeurs. Ce sont des arguments de fonction, le côté droit d'une affectation, etc. Voici un exemple d'expression:
3 * 7

La distinction entre les instructions et les expressions est mieux illustrée par le fait que JavaScript a deux façons différentes de faire if-then-else soit comme une instruction:

var x;
if (y >= 0) {
    x = y;
} else {
    x = -y;
}

ou comme une expression:

var x = y >= 0 ? y : -y;

Vous pouvez utiliser ce dernier comme argument de fonction (mais pas le premier):

myFunction(y >= 0 ? y : -y)

Enfin, partout où JavaScript attend une instruction, vous pouvez également utiliser une expression; par exemple:

foo(7, 1);

La ligne entière est une instruction (appelée instruction d'expression), mais l'appel de la fonction foo(7, 1) est une expression.

Commentaires

Les points-virgules sont facultatifs dans JavaScript. Cependant, je recommande toujours de les inclure, car sinon JavaScript peut deviner mal la fin d'une instruction. Les détails sont expliqués dans l'insertion automatique de points-virgules.

Les points-virgules terminent les instructions, mais pas les blocs. Il y a un cas où vous verrez un point-virgule après un bloc: une expression de fonction est une expression qui se termine par un bloc. Si une telle expression arrive en dernier dans une instruction, elle est suivie d'un point-virgule:

// Pattern: var _ = ___;
var x = 3 * 7;
var f = function () { };  // function expr. inside var decl.

Commentaires

JavaScript a deux types de commentaires: les commentaires en une ligne et les commentaires en plusieurs lignes.

x++; // single-line comment

Les commentaires à plusieurs lignes sont délimités par * et *:

/* This is
   a multiline
   comment.
 */

Variables et affectation

Les variables en JavaScript sont déclarées avant d'être utilisées:

var foo;  // declare variable `foo`

Nommé

Vous pouvez déclarer une variable et assigner une valeur en même temps:

var foo = 6;

Vous pouvez également attribuer une valeur à une variable existante:

foo = 4;  // change variable `foo`

Les opérateurs de répartition composée

Il existe des opérateurs d'affectation composés tels que +=. Les deux affectations suivantes sont équivalentes:

x += 1;
x = x + 1;

Identificateurs et noms de variables

Les identifiants sont des noms qui jouent différents rôles syntaxiques en JavaScript.

En gros, le premier caractère d'un identifiant peut être n'importe quelle lettre Unicode, un signe de dollar ($) ou un soulignement (_).

arg0
_tmp
$elem
π

Les identifiants suivants sont des mots réservés, ils font partie de la syntaxe et ne peuvent pas être utilisés comme noms de variables (y compris les noms de fonctions et de paramètres):

img

Les trois identifiants suivants ne sont pas des mots réservés, mais vous devez les traiter comme s'ils l'étaient:

img

Enfin, vous devriez également rester à l'écart des noms des variables globales standard. Vous pouvez les utiliser pour les variables locales sans casser quoi que ce soit, mais votre code devient toujours déroutant.

Les valeurs

JavaScript possède de nombreuses valeurs que l'on attend des langages de programmation: booléens, nombres, chaînes, tableaux, etc. Toutes les valeurs de JavaScript ont des propriétés. Chaque propriété a une clé (ou un nom) et une valeur. Vous pouvez penser aux propriétés comme des champs d'un enregistrement. Vous utilisez l'opérateur point (.) pour lire une propriété:

value.propKey

Par exemple, la chaîne abc a la longueur de propriété:

> var str = 'abc';
> str.length
3

Le précédent peut aussi s'écrire:

> 'abc'.length
3
The dot operator is also used to assign a value to a property:

> var obj = {};  // empty object
> obj.foo = 123; // create property `foo`, set it to 123
123
> obj.foo
123

Et vous pouvez l'utiliser pour appeler des méthodes:

> 'hello'.toUpperCase()
'HELLO'

Dans l'exemple précédent, nous avons appelé la méthode toUpperCase() sur la valeur hello.

Des valeurs primitives contre des objets

JavaScript fait une distinction quelque peu arbitraire entre les valeurs:

  • Les valeurs primitives sont les booleans, les nombres, les chaînes, nul et indéfini.
  • Les autres valeurs sont des objets. Une différence majeure entre les deux est la façon dont ils sont comparés; chaque objet a une identité unique et n'est (strictement) égal qu'à lui-même:
> var obj1 = {};  // an empty object
> var obj2 = {};  // another empty object
> obj1 === obj2
false
> obj1 === obj1
true

En revanche, toutes les valeurs primitives codant la même valeur sont considérées comme les mêmes:

> var prim1 = 123;
> var prim2 = 123;
> prim1 === prim2
true

Les deux sections suivantes expliquent plus en détail les valeurs et les objets primitifs.

Des valeurs primitives

Voici toutes les valeurs primitives (ou primitives en abrégé):

  • Booleans: vrai, faux (voir Booleans)
  • Nombres: 1736, 1.351 (voir Nombres)
  • Les cordes: abc, abc (voir les cordes)
  • Deux non-valeurs: non définies, nulles (voir non définies et nulles)

Les primitifs ont les caractéristiques suivantes:

Comparé par valeur

Le contenu est comparé:

> 3 === 3
true
> 'abc' === 'abc'
true

Toujours immuable Les propriétés ne peuvent pas être modifiées, ajoutées ou supprimées:

> var str = 'abc';

> str.length = 1; // try to change property `length`
> str.length      // ⇒ no effect
3

> str.foo = 3; // try to create property `foo`
> str.foo      // ⇒ no effect, unknown property
undefined

(La lecture d'une propriété inconnue renvoie toujours indéfinie.)

Objets

Toutes les valeurs non primitives sont des objets.

  • Objets simples, qui peuvent être créés par des objets littéraux (voir Objets uniques):
{
    firstName: 'Jane',
    lastName: 'Doe'
}

L'objet précédent a deux propriétés: la valeur de la propriété firstName est Jane et la valeur de la propriété lastName est Doe.

  • Arrays, qui peuvent être créés par des littéraux d'array (voir Arrays):
[ 'apple', 'banana', 'cherry' ]

Le tableau précédent comporte trois éléments auxquels on peut accéder via des indices numériques.

  • Expressions régulières, qui peuvent être créées par des expressions régulières littérales (voir Expressions régulières):
/^a+b+$/

Les objets présentent les caractéristiques suivantes:

Comparé par référence

Les identités sont comparées; chaque valeur a sa propre identité:

> ({} === {})  // two different empty objects
false

> var obj1 = {};
> var obj2 = obj1;
> obj1 === obj2
true

Modifiable par défaut

Vous pouvez normalement modifier, ajouter et supprimer librement des propriétés (voir Objets uniques):

> var obj = {};
> obj.foo = 123; // add property `foo`
> obj.foo
123

non défini et nul

La plupart des langages de programmation ont des valeurs désignant des informations manquantes.

  • undefined signifie pas de valeur. Les variables non initialisées sont indéfinies:
> var foo;
> foo
undefined

Les paramètres manquants ne sont pas définis:

> function f(x) { return x }
> f()
undefined

Si vous lisez une propriété inexistante, vous obtenez indéfinie:

> var obj = {}; // empty object
> obj.foo
undefined
  • null signifie aucun objet. Il est utilisé comme non-valeur chaque fois qu'un objet est attendu (paramètres, dernier dans une chaîne d'objets, etc.).

Avertissement

undefined et null n'ont pas de propriétés, pas même les méthodes standard telles que toString().

Vérification de non-défini ou nul

Les fonctions vous permettent normalement d'indiquer une valeur manquante via undefined ou null. Vous pouvez faire de même via une vérification explicite:

if (x === undefined || x === null) {
    ...
}

Vous pouvez également exploiter le fait que les deux indéfinis et nul sont considérés comme faux:

if (!x) {
    ...
}

Avertissement

false, 0, NaN et sont également considérés comme faux (voir Vrai et Faux).

Catégorisation des valeurs à l'aide du type et de l'instance de

Il existe deux opérateurs pour catégoriser les valeurs: typeof est principalement utilisé pour les valeurs primitives, tandis que instanceof est utilisé pour les objets. Le type ressemble à ceci:

typeof value

Il renvoie une chaîne décrivant le type de valeur. Voici quelques exemples:

> typeof true
'boolean'
> typeof 'abc'
'string'
> typeof {} // empty object literal
'object'
> typeof [] // empty array literal
'object'

Le tableau suivant répertorie tous les résultats de type:

img

typeof null retour object est un bug qui ne peut pas être corrigé, car il briserait le code existant.

L'exemple est le suivant:

value instanceof Constr

Il renvoie true si la valeur est un objet qui a été créé par le constructeur Constr (voir Constructors: Factories for Objects).

> var b = new Bar();  // object created by constructor Bar
> b instanceof Bar
true

> {} instanceof Object
true
> [] instanceof Array
true
> [] instanceof Object  // Array is a subconstructor of Object
true

> undefined instanceof Object
false
> null instanceof Object
false

Les booléens

Le type booléen primitif comprend les valeurs vrai et faux.

  • Opérateurs logiques binaires: && (et),
  • Préfixe opérateur logique:! (Non)
  • Opérateurs de comparaison:Opérateurs d'égalité: ===,!==, ==,!=
  • Opérateurs d'ordre (pour les chaînes et les nombres): >, >=, <, <=

Véridique et faux

Chaque fois que JavaScript s'attend à une valeur booléenne (par exemple, pour la condition d'une instruction if), n'importe quelle valeur peut être utilisée. Elle sera interprétée comme vraie ou fausse. Les valeurs suivantes sont interprétées comme fausse:

  • non défini, nul
  • Boolean: faux
  • Nombre: 0, NaN
  • - Je ne sais pas.

Toutes les autres valeurs (y compris tous les objets!) sont considérées comme vraies. Les valeurs interprétées comme fausses sont appelées faux, et les valeurs interprétées comme vraies sont appelées vraies. Boolean(), appelé comme une fonction, convertit son paramètre en boolean. Vous pouvez l'utiliser pour tester comment une valeur est interprétée:

> Boolean(undefined)
false
> Boolean(0)
false
> Boolean(3)
true
> Boolean({}) // empty object
true
> Boolean([]) // empty array
true

Opérateurs logiques binaires

Les opérateurs logiques binaires en JavaScript sont des courts-circuits, c'est-à-dire que si le premier opérand est suffisant pour déterminer le résultat, le deuxième opérand n'est pas évalué.

false && foo()
true  || foo()

En outre, les opérateurs logiques binaires renvoient l'un de leurs opérands, qui peut ou non être un booléen.

Et (&&)

Si le premier opérand est faux, retournez-le. Sinon, retournez le deuxième opérand:

> NaN && 'abc'
NaN
> 123 && 'abc'
'abc'

Ou encore:

Si le premier opérand est vrai, retournez-le. Sinon, retournez le deuxième opérand:

> 'abc' || 123
'abc'
> '' || 123
123

Opérateurs de l'égalité

JavaScript a deux types d'égalité:

  • Normalement, ou plénient, (en) égalité: == et!=
  • Strict (in) equality: === et!==

L'égalité normale considère (trop) de valeurs comme égales (les détails sont expliqués dans l'égalité normale (==,!=)), ce qui peut cacher des bugs. Par conséquent, il est toujours recommandé d'utiliser une égalité stricte.

Numéros

Tous les nombres en JavaScript sont en virgule flottante:

> 1 === 1.0
true

Les numéros spéciaux sont les suivants:

NaN (non un nombre) Une valeur d'erreur:

> Number('xyz')  // 'xyz' can’t be converted to a number
NaN

L' infini C'est aussi une valeur d'erreur:

> 3 / 0
Infinity
> Math.pow(2, 1024)  // number too large
Infinity

L'infini est plus grand que n'importe quel autre nombre (sauf NaN). De même, -Infinity est plus petit que n'importe quel autre nombre (sauf NaN). Cela rend ces nombres utiles comme valeurs par défaut (par exemple, lorsque vous recherchez un minimum ou un maximum).

Les opérateurs

JavaScript possède les opérateurs arithmétiques suivants (voir Opérateurs arithmétiques):

  • Ajout: numéro 1 + numéro 2
  • Soustraction: numéro 1 - numéro 2
  • Multiplication: nombre1 * nombre2
  • Division: numéro 1 / numéro 2
  • Reste: n°1 % n°2
  • Incrémentation: ++variable, variable++
  • Décrément: variable, variable
  • Négatif: -valeur
  • Conversion en nombre: + valeur

L'objet global Math (voir Math) fournit plus d'opérations arithmétiques, via des fonctions.

JavaScript possède également des opérateurs pour les opérations bitwise (par exemple, bitwise And; voir Bitwise Operators).

Les cordes

Les chaînes peuvent être créées directement via des littéraux de chaîne. Ces littéraux sont délimités par des guillemets simples ou doubles. Le backslash () évite les caractères et produit quelques caractères de contrôle. Voici quelques exemples:

'abc'
"abc"

'Did she say "Hello"?'
"Did she say \"Hello\"?"

'That\'s nice!'
"That's nice!"

'Line 1\nLine 2'  // newline
'Backlash: \\'

Les caractères individuels sont accessibles par des parenthèses carrées:

> var str = 'abc';
> str[1]
'b'

La longueur de propriété compte le nombre de caractères dans la chaîne:

> 'abc'.length
3

Comme tous les primitifs, les chaînes sont immuables; vous devez créer une nouvelle chaîne si vous voulez en changer une existante.

Opérateurs de chaîne

Les chaînes sont concaténées via l'opérateur plus (+), qui convertit l'autre opérand en chaîne si l'un des opérands est une chaîne:

> var messageCount = 3;
> 'You have ' + messageCount + ' messages'
'You have 3 messages'

Pour concatener des chaînes en plusieurs étapes, utilisez l'opérateur +=:

> var str = '';
> str += 'Multiple ';
> str += 'pieces ';
> str += 'are concatenated.';
> str
'Multiple pieces are concatenated.'

Méthodes de chaîne

Les chaînes ont de nombreuses méthodes utiles (voir méthodes de prototypage de chaînes). Voici quelques exemples:

> 'abc'.slice(1)  // copy a substring
'bc'
> 'abc'.slice(1, 2)
'b'

> '\t xyz  '.trim()  // trim whitespace
'xyz'

> 'mjölnir'.toUpperCase()
'MJÖLNIR'

> 'abc'.indexOf('b')  // find a string
1
> 'abc'.indexOf('x')
-1

Déclarations

Les conditionnels et les boucles en JavaScript sont introduits dans les sections suivantes.

Conditionnels

L'instruction if a une clause then et une clause else optionnelle qui sont exécutées en fonction d'une condition booléenne:

if (myvar === 0) {
    // then
}

if (myvar === 0) {
    // then
} else {
    // else
}

if (myvar === 0) {
    // then
} else if (myvar === 1) {
    // else-if
} else if (myvar === 2) {
    // else-if
} else {
    // else
}

Je recommande toujours d'utiliser des crochets (ils désignent des blocs de zéro ou plus d'instructions). Mais vous n'êtes pas obligé de le faire si une clause n'est qu'une seule instruction (il en va de même pour les instructions de flux de contrôle pour et pendant):

if (x < 0) return -x;

Ce qui suit est une instruction de commutation. La valeur de fruit détermine quel cas est exécuté:

switch (fruit) {
    case 'banana':
        // ...
        break;
    case 'apple':
        // ...
        break;
    default:  // all other cases
        // ...
}

L'opérand après le cas peut être n'importe quelle expression; il est comparé via === avec le paramètre de commutation.

Boucles

La boucle for a le format suivant:

for (⟦«init»⟧; ⟦«condition»⟧; ⟦«post_iteration»⟧)
    «statement»

init est exécuté au début de la boucle. condition est vérifiée avant chaque itération de boucle; si elle devient fausse, alors la boucle est terminée. post_iteration est exécuté après chaque itération de boucle.

Cet exemple imprime tous les éléments du tableau arr sur la console:

for (var i=0; i < arr.length; i++) {
    console.log(arr[i]);
}

La boucle while continue de boucler sur son corps pendant que son état est maintenu:

// Same as for loop above:
var i = 0;
while (i < arr.length) {
    console.log(arr[i]);
    i++;
}

La boucle do-while continue de boucler sur son corps pendant que sa condition est maintenue.

do {
    // ...
} while (condition);

Dans toutes les boucles:

  • La rupture laisse la boucle.
  • continue commence une nouvelle itération de boucle.

Les fonctions

Une façon de définir une fonction est via une déclaration de fonction:

function add(param1, param2) {
    return param1 + param2;
}

Le code précédent définit une fonction, add, qui a deux paramètres, param1 et param2, et renvoie la somme des deux paramètres.

> add(6, 1)
7
> add('a', 'b')
'ab'

Une autre façon de définir add() est d'assigner une expression de fonction à une variable add:

var add = function (param1, param2) {
    return param1 + param2;
};

Une expression de fonction produit une valeur et peut donc être utilisée pour passer directement des fonctions en tant qu'arguments à d'autres fonctions:

someOtherFunction(function (p1, p2) { ... });

Les déclarations de fonctions sont hissées

Les déclarations de fonctions sont hissées déplacées dans leur intégralité au début de l'étendue actuelle.

function foo() {
    bar();  // OK, bar is hoisted
    function bar() {
        ...
    }
}

Notez que, bien que les déclarations var soient également hissées (voir Les variables sont hissées), les affectations qu'elles effectuent ne sont pas:

function foo() {
    bar();  // Not OK, bar is still undefined
    var bar = function () {
        // ...
    };
}

Les arguments de la variable spéciale

Vous pouvez appeler n'importe quelle fonction en JavaScript avec un nombre arbitraire d'arguments; le langage ne se plaindra jamais. Il rendra cependant tous les paramètres disponibles via les arguments de variables spéciales. arguments ressemble à un tableau, mais n'a aucune des méthodes de tableau:

> function f() { return arguments }
> var args = f('a', 'b', 'c');
> args.length
3
> args[0]  // read element at index 0
'a'

Trop ou trop peu de disputes

Utilisons la fonction suivante pour explorer comment trop ou trop peu de paramètres sont manipulés en JavaScript (la fonction toArray( est montrée dans Convertir des arguments en un Array):

function f(x, y) {
    console.log(x, y);
    return toArray(arguments);
}

Des paramètres supplémentaires seront ignorés (sauf par les arguments):

> f('a', 'b', 'c')
a b
[ 'a', 'b', 'c' ]

Les paramètres manquants rendront la valeur indéfinie:

> f('a')
a undefined
[ 'a' ]
> f()
undefined undefined
[]

Paramètres facultatifs

Voici un modèle commun pour attribuer des valeurs par défaut aux paramètres:

function pair(x, y) {
    x = x || 0;  // (1)
    y = y || 0;
    return [ x, y ];
}

Dans la ligne (1), l'opérateur de référence renvoie x s'il est vrai (pas nul, indéfini, etc.).

> pair()
[ 0, 0 ]
> pair(3)
[ 3, 0 ]
> pair(3, 5)
[ 3, 5 ]

La mise en place d'une arité

Si vous voulez imposer une arité (un nombre spécifique de paramètres), vous pouvez vérifier arguments.length:

function pair(x, y) {
    if (arguments.length !== 2) {
        throw new Error('Need exactly 2 arguments');
    }
    ...
}

Conversion d'arguments dans un tableau

arguments n'est pas un tableau, il n'est qu'un tableau (voir Array-Like Objects and Generic Methods). Il a une longueur de propriété, et vous pouvez accéder à ses éléments via des indices entre parenthèses carrées. Vous ne pouvez cependant pas supprimer des éléments ou invoquer l'une des méthodes de tableau sur celui-ci. Ainsi, vous devez parfois convertir des arguments en un tableau, ce que fait la fonction suivante (elle est expliquée dans Array-Like Objects and Generic Methods):

function toArray(arrayLikeObject) {
    return Array.prototype.slice.call(arrayLikeObject);
}

Traitement des exceptions

La manière la plus courante de traiter les exceptions (voir chapitre 14) est la suivante:

function getPerson(id) {
    if (id < 0) {
        throw new Error('ID must not be negative: '+id);
    }
    return { id: id }; // normally: retrieved from database
}

function getPersons(ids) {
    var result = [];
    ids.forEach(function (id) {
        try {
            var person = getPerson(id);
            result.push(person);
        } catch (exception) {
            console.log(exception);
        }
    });
    return result;
}

La clause try entoure le code critique, et la clause catch est exécutée si une exception est jetée à l'intérieur de la clause try.

> getPersons([2, -5, 137])
[Error: ID must not be negative: -5]
[ { id: 2 }, { id: 137 } ]

Mode strict

Le mode strict (voir Mode strict) permet plus d'avertissements et rend JavaScript un langage plus propre (le mode non strict est parfois appelé sloppy mode).

'use strict';

Vous pouvez également activer le mode strict par fonction:

function functionInStrictMode() {
    'use strict';
}

Portée variable et fermetures

En JavaScript, vous déclarez des variables via var avant de les utiliser:

> var x;
> x
undefined
> y
ReferenceError: y is not defined

Vous pouvez déclarer et initialiser plusieurs variables avec une seule instruction var:

var x = 1, y = 2, z = 3;

Mais je recommande d'utiliser une instruction par variable (la raison est expliquée dans la syntaxe).

var x = 1;
var y = 2;
var z = 3;

En raison de l'élévation (voir Variables Are Hoisted), il est généralement préférable de déclarer des variables au début d'une fonction.

Les variables sont fonctionnelles

La portée d'une variable est toujours la fonction complète (par opposition au bloc actuel).

function foo() {
    var x = -512;
    if (x < 0) {  // (1)
        var tmp = -x;
        ...
    }
    console.log(tmp);  // 512
}

Nous pouvons voir que la variable tmp n'est pas limitée au bloc commençant à la ligne (1); elle existe jusqu'à la fin de la fonction.

Les variables sont augmentées

Chaque déclaration de variable est hissée: la déclaration est déplacée au début de la fonction, mais les affectations qu'elle effectue restent posées.

function foo() {
    console.log(tmp); // undefined
    if (false) {
        var tmp = 3;  // (1)
    }
}

En interne, la fonction précédente est exécutée comme ceci:

function foo() {
    var tmp;  // hoisted declaration
    console.log(tmp);
    if (false) {
        tmp = 3;  // assignment stays put
    }
}

Fermetures

Chaque fonction reste connectée aux variables des fonctions qui l'entourent, même après avoir quitté la portée dans laquelle elle a été créée.

function createIncrementor(start) {
    return function () {  // (1)
        start++;
        return start;
    }
}

La fonction commençant à la ligne (1) quitte le contexte dans lequel elle a été créée, mais reste connectée à une version en direct de start:

> var inc = createIncrementor(5);
> inc()
6
> inc()
7
> inc()
8

Une clôture est une fonction plus la connexion aux variables de ses champs environnants.

Le modèle IIFE: introduire un nouveau champ d'application

Parfois, vous voulez introduire une nouvelle variable scope, par exemple, pour empêcher une variable de devenir globale. En JavaScript, vous ne pouvez pas utiliser un bloc pour le faire; vous devez utiliser une fonction. Mais il existe un modèle pour utiliser une fonction de manière similaire à un bloc.

(function () {  // open IIFE
    var tmp = ...;  // not a global variable
}());  // close IIFE

Assurez-vous de taper l'exemple précédent exactement comme indiqué (à l'exception des commentaires). Un IIFE est une expression de fonction qui est appelée immédiatement après sa définition.

Cas d'utilisation IIFE: partage par inadvertance via des fermetures

Les clôtures gardent leurs connexions aux variables extérieures, ce qui n'est parfois pas ce que vous voulez:

var result = [];
for (var i=0; i < 5; i++) {
    result.push(function () { return i });  // (1)
}
console.log(result[1]()); // 5 (not 1)
console.log(result[3]()); // 5 (not 3)

La valeur renvoyée dans la ligne (1) est toujours la valeur actuelle de i, et non la valeur qu'elle avait lorsque la fonction a été créée. Après la fin de la boucle, i a la valeur 5, c'est pourquoi toutes les fonctions dans le tableau renvoient cette valeur. Si vous voulez que la fonction dans la ligne (1) reçoive un instantané de la valeur actuelle de i, vous pouvez utiliser un IIFE:

for (var i=0; i < 5; i++) {
    (function () {
        var i2 = i; // copy current i
        result.push(function () { return i2 });
    }());
}

Objets et constructeurs

Cette section couvre deux mécanismes de base orientés objet de JavaScript: les objets simples et les constructeurs (qui sont des usines d'objets, similaires aux classes dans d'autres langages).

Objectifs uniques

Comme toutes les valeurs, les objets ont des propriétés. Vous pourriez, en fait, considérer un objet comme un ensemble de propriétés, où chaque propriété est une paire (clé, valeur). La clé est une chaîne, et la valeur est n'importe quelle valeur JavaScript.

En JavaScript, vous pouvez directement créer des objets simples, via des littéraux d'objets:

'use strict';
var jane = {
    name: 'Jane',

    describe: function () {
        return 'Person named '+this.name;
    }
};

Vous pouvez lire (get) et écrire (set) propriétés:

> jane.name  // get
'Jane'
> jane.name = 'John';  // set
> jane.newProperty = 'abc';  // property created automatically

Les propriétés à valeur de fonction telles que describe sont appelées méthodes.

> jane.describe()  // call method
'Person named John'
> jane.name = 'Jane';
> jane.describe()
'Person named Jane'

L'opérateur in vérifie si une propriété existe:

> 'newProperty' in jane
true
> 'foo' in jane
false

Si vous lisez une propriété qui n'existe pas, vous obtenez la valeur undefined.

> jane.newProperty !== undefined
true
> jane.foo !== undefined
false

L'opérateur supprimer supprime une propriété:

> delete jane.newProperty
true
> 'newProperty' in jane
false

Clés de propriété arbitraires

Une clé de propriété peut être n'importe quelle chaîne. Jusqu'à présent, nous avons vu des clés de propriété dans des littéraux d'objets et après l'opérateur de points. Cependant, vous ne pouvez les utiliser de cette façon que s'ils sont des identifiants (voir Identifiants et noms de variables). Si vous voulez utiliser d'autres chaînes comme clés, vous devez les citer dans un littérale d'objet et utiliser des crochets carrés pour obtenir et définir la propriété:

> var obj = { 'not an identifier': 123 };
> obj['not an identifier']
123
> obj['not an identifier'] = 456;

Les parenthèses carrées vous permettent également de calculer la clé d'une propriété:

> var obj = { hello: 'world' };
> var x = 'hello';

> obj[x]
'world'
> obj['hel'+'lo']
'world'

Méthodes d'exploitation

Si vous extraisez une méthode, elle perd sa connexion avec l'objet.

À titre d'exemple, revenons à l'objet précédent jane:

'use strict';
var jane = {
    name: 'Jane',

    describe: function () {
        return 'Person named '+this.name;
    }
};

Nous voulons extraire la méthode describe de jane, la mettre dans une variable func, et l'appeler.

> var func = jane.describe;
> func()
TypeError: Cannot read property 'name' of undefined

La solution est d'utiliser la méthode bind() que toutes les fonctions ont.

> var func2 = jane.describe.bind(jane);
> func2()
'Person named Jane'

Fonctions au sein d'une méthode

Chaque fonction a sa propre variable spéciale this. Ceci est gênant si vous imbriquez une fonction à l'intérieur d'une méthode, car vous ne pouvez pas accéder à la méthode this à partir de la fonction. Voici un exemple où nous appelons forEach avec une fonction pour itérer sur un tableau:

var jane = {
    name: 'Jane',
    friends: [ 'Tarzan', 'Cheeta' ],
    logHiToFriends: function () {
        'use strict';
        this.friends.forEach(function (friend) {
            // `this` is undefined here
            console.log(this.name+' says hi to '+friend);
        });
    }
}

L'appel au journal HiToFriends produit une erreur:

> jane.logHiToFriends()
TypeError: Cannot read property 'name' of undefined

Voyons deux façons de résoudre ce problème.

logHiToFriends: function () {
    'use strict';
    var that = this;
    this.friends.forEach(function (friend) {
        console.log(that.name+' says hi to '+friend);
    });
}

Ou, forEach a un deuxième paramètre qui vous permet de fournir une valeur pour cela:

logHiToFriends: function () {
    'use strict';
    this.friends.forEach(function (friend) {
        console.log(this.name+' says hi to '+friend);
    }, this);
}

Les expressions de fonction sont souvent utilisées comme arguments dans les appels de fonction en JavaScript.

Constructeurs: usines d'objets

Jusqu'à présent, vous pensez peut-être que les objets JavaScript ne sont que des cartes de chaînes vers des valeurs, une notion suggérée par les littéraux d'objets JavaScript, qui ressemblent aux littéraux de carte / dictionnaire d'autres langages. Cependant, les objets JavaScript prennent également en charge une fonctionnalité vraiment orientée objet: l'héritage. Cette section n'explique pas complètement comment fonctionne l'héritage JavaScript, mais elle vous montre un modèle simple pour vous aider à démarrer. Consultez le chapitre 17 si vous voulez en savoir plus.

En plus d'être des fonctions et des méthodes réelles, les fonctions jouent un autre rôle dans JavaScript: elles deviennent des constructeurs pour les objets si elles sont appelées via le nouvel opérateur.

// Set up instance data
function Point(x, y) {
    this.x = x;
    this.y = y;
}
// Methods
Point.prototype.dist = function () {
    return Math.sqrt(this.x*this.x + this.y*this.y);
};

Nous pouvons voir qu'un constructeur a deux parties. Premièrement, la fonction Point définit les données d'instance. Deuxièmement, la propriété Point.prototype contient un objet avec les méthodes. Les données précédentes sont spécifiques à chaque instance, tandis que les données suivantes sont partagées entre toutes les instances.

Pour utiliser Point, nous l'invoquons via le nouvel opérateur:

> var p = new Point(3, 5);
> p.x
3
> p.dist()
5.830951894845301

p est une instance de Point:

> p instanceof Point
true

Les tableaux

Les tableaux sont des séquences d'éléments auxquelles on peut accéder via des indices entiers commençant à zéro.

Légendaire de tableau

Les littéraux de tableau sont utiles pour créer des tableaux:

> var arr = [ 'a', 'b', 'c' ];

Le tableau précédent comporte trois éléments: les chaînes a, b et c. Vous pouvez y accéder via des indices entiers:

> arr[0]
'a'
> arr[0] = 'x';
> arr
[ 'x', 'b', 'c' ]

La propriété longueur indique le nombre d'éléments d'un tableau.

> var arr = ['a', 'b'];
> arr.length
2

> arr[arr.length] = 'c';
> arr
[ 'a', 'b', 'c' ]
> arr.length
3

> arr.length = 1;
> arr
[ 'a' ]

L'opérateur in fonctionne aussi pour les tableaux:

> var arr = [ 'a', 'b', 'c' ];
> 1 in arr // is there an element at index 1?
true
> 5 in arr // is there an element at index 5?
false

Notez que les tableaux sont des objets et peuvent donc avoir des propriétés d'objet:

> var arr = [];
> arr.foo = 123;
> arr.foo
123

Méthodes de séquence

Les tableaux ont de nombreuses méthodes (voir les méthodes de prototypes de tableaux). Voici quelques exemples:

> var arr = [ 'a', 'b', 'c' ];

> arr.slice(1, 2)  // copy elements
[ 'b' ]
> arr.slice(1)
[ 'b', 'c' ]

> arr.push('x')  // append an element
4
> arr
[ 'a', 'b', 'c', 'x' ]

> arr.pop()  // remove last element
'x'
> arr
[ 'a', 'b', 'c' ]

> arr.shift()  // remove first element
'a'
> arr
[ 'b', 'c' ]

> arr.unshift('x')  // prepend an element
3
> arr
[ 'x', 'b', 'c' ]

> arr.indexOf('b')  // find the index of an element
1
> arr.indexOf('y')
-1

> arr.join('-')  // all elements in a single string
'x-b-c'
> arr.join('')
'xbc'
> arr.join()
'x,b,c'

Iteration sur les tableaux

Il existe plusieurs méthodes de tableau pour l'itération sur des éléments (voir Iteration (Non destructive)). Les deux plus importantes sont forEach et map.

forEach itère sur un tableau et remet l'élément actuel et son index à une fonction:

[ 'a', 'b', 'c' ].forEach(
    function (elem, index) {  // (1)
        console.log(index + '. ' + elem);
    });

Le code précédent donne la sortie suivante:

0. a
1. b
2. c

Notez que la fonction dans la ligne (1) est libre d'ignorer les arguments.

map crée un nouveau tableau en appliquant une fonction à chaque élément d'un tableau existant:

> [1,2,3].map(function (x) { return x*x })
[ 1, 4, 9 ]

Expressions régulières

JavaScript prend en charge les expressions régulières, délimitées par des traits:

/^abc$/
/[A-Za-z0-9]+/

Test de méthode: y a-t-il une correspondance?

> /^a+b+$/.test('aaab')
true
> /^a+b+$/.test('aaa')
false

Méthode exec ((): Groupes de correspondance et de capture

> /a(b+)a/.exec('_abbba_aba_')
[ 'abbba', 'bbb' ]

Le tableau retourné contient la correspondance complète à l'index 0, la capture du premier groupe à l'index 1, etc. Il existe un moyen (discuté dans RegExp.prototype.exec: Capture Groups) d'appeler cette méthode à plusieurs reprises pour obtenir toutes les correspondances.

Méthode de remplacement ((): Rechercher et remplacer

> '<a> <bbb>'.replace(/<(.*?)>/g, '[$1]')
'[a] [bbb]'

Le premier paramètre de remplacement doit être une expression régulière avec un drapeau /g; sinon, seule la première occurrence est remplacée.

Les maths

Les mathématiques sont des objets avec des fonctions arithmétiques.

> Math.abs(-2)
2

> Math.pow(3, 2)  // 3 to the power of 2
9

> Math.max(2, -1, 5)
5

> Math.round(1.9)
2

> Math.PI  // pre-defined constant for π
3.141592653589793

> Math.cos(Math.PI)  // compute the cosine for 180°
-1

Plus de