JavaScript : les bases
Michel Buffa
Avril 2012
buffa@unice.fr
Déclaration, initialisation
var a; var ceciEstUneVariable; var _et_ceci_aussi; var mix12trois; // invalide ! var 2three4five; // ne peut commencer par un chiffre ! var a = 1 var v1, v2, v3 = 'hello', v4 = 4, v5; // Attentions aux majuscules/minuscules var case_matters = 'lower'; var CASE_MATTERS = 'upper';
Très pratiques pour tester la syntaxe JavaScript
>>> 1 + 2 3 >>> var a = 1; >>> var b = 2; >>> a + 1 2 >>> b + 2 4 >>> a + b 3 >>> var c = a + b; >>> c 3
>>> 1 + 2 3 >>> 99.99 – 11 88.99 >>> 2 * 3 6 >>> 6 / 4 1.5
Modulo
>>> 6 % 3 0 >>> 5 % 3 2 >>> 4 % 2 0 >>> 5 % 2 1
>>> var a = 123; var b = a++; >>> b 123 >>> a 124 >>> var a = 123; var b = ++a; >>> b 124 >>> a 124 >>> var a = 123; var b = a--; >>> b 123 >>> a 122
>>> var a = 5; >>> a += 3; // équivalent à a = a + 3; 8 >>> a -= 3; 5 >>> a *= 2; 10 >>> a /= 5; 2 >>> a %= 2; // équivalent à a = a % 2; 0
Tout ce qui n'est pas d'un des types ci-dessus est un objet.
typeof : renvoie un objet de stype String, qui peut valoir "number", "string", "boolean", "undefined", "object", ou "function"
>>> var n = 1; >>> typeof n; "number" >>> n = 1234; >>> typeof n; "number" >>> var n2 = 1.23; >>> typeof n; "number" >>> typeof 123; "number"
>>> var n3 = 0377; >>> typeof n3; "number" >>> n3; 255 >>> var n4 = 0x00; >>> typeof n4; "number" >>> n4; 0 >>> var n5 = 0xff; >>> typeof n5; "number" >>> n5; 255
>>> 1e1 10 >>> 1e+1 10 >>> 2e+3 2000 >>> typeof 2e+3; "number" >>> 2e-3 0.002 >>> 123.456E-3 0.123456 >>> typeof 2e-3 "number"
>>> Infinity Infinity >>> typeof Infinity "number" >>> 1e309 Infinity >>> 1e308 1e+308 >>> var a = 6 / 0; >>> a Infinity >>> var i = -Infinity; >>> i -Infinity >>> typeof i "number"
>>> Infinity - Infinity NaN >>> -Infinity + Infinity NaN
N'importe quelle opération avec Infinity donne Infinity comme résultat.
>>> Infinity - 20 Infinity >>> -Infinity * 3 -Infinity >>> Infinity / 2 Infinity >>> Infinity - 99999999999999999 Infinity
NaN est une valeur spéciale et son type est "Number" !
>>> typeof NaN "number" >>> var a = NaN; >>> a NaN
NaN = résultat d'opérations arithmétiques impossibles :
>>> var a = 10 * "f"; >>> a NaN >>> 1 + 2 + a NaN
Une chaine = entre simple ou double quotes "Hello" ou 'hello'...
>>> var s = "quelques caractères"; >>> typeof s; "string" >>> var s = 'quelques caractères et des nombres 123 5.87'; >>> typeof s; "string" >>> var s = '1'; >>> typeof s; "string" >>> var s = ""; typeof s; "string"
Comme en Java, l'opérateur "+" permet de concaténer des chaines...
>>> var s1 = "un"; var s2 = "deux"; var s = s1 + s2; s; "undeux" >>> typeof s; "string"
Un nombre sous forme de String dans une expression arithmétique est converti en Number, sauf si la formule est une addition pure.
>>> var s = '1'; s = 3 * s; typeof s; "number" >>> s 3 >>> var s = '1'; s++; typeof s; "number" >>> s 2 >>> var s = "100"; typeof s; "string" >>> s = s * 1; 100 >>> typeof s; "number" >>> var d = '101 dalmatiens'; >>> d * 1 NaN
On concatène avec une chaine vide, en début d'expression
>>> var n = 1; >>> typeof n; "number" >>> n = "" + n; "1" >>> typeof n; "string"
>>> var s = 'I don\'t know'; >>> var s = "I don\'t know"; >>> var s = "I don't know"; >>> var s = '"Hello", he said.'; >>> var s = "\"Hello\", he said."; Escaping the escape: >>> var s = "1\\2"; s; "1\2" >>> var s = '\n1\n2\n3\n'; >>> s " 1 2 3 "
>>> var s = '1\r2'; >>> var s = '1\n\r2'; >>> var s = '1\r\n2'; // les trois donnent : >>> s "1 2" // tabulation >>> var s = "1\t2" >>> s "1 2" // Ecrire en bulgare : >>> "\u0421\u0442\u043E\u044F\u043D" "Стoян"
>>> var b = true; typeof b; "boolean" >>> var b = false; typeof b; "boolean"
Mais... si on met entre quotes :
>>> var b = "true"; typeof b; "string"
Ce sont les mêmes qu'en java : && (ET), || (OU), ! (NOT)
>>> var b = !true; >>> b; false >>> var b = !!true; >>> b; true >>> var b = "one"; >>> !b; false >>> var b = "one"; >>> !!b; true
Dans une expression booléene avec des opérateurs logiques, les valeurs non booléennes sont converties implicitement.
0, null, Undefined, false, NaN, la chaine vide "" sont converties en false
Toute le reste est converti en true
Astuce pour convertir en booléen :
!!a
* avant + et -
>>> 1 + 2 * 3 7 >>> 1 + (2 * 3) 7
! avant && et ||
>>> false && false || true && true true >>> (false && false) || (true && true) true
Conseil : utilisez des parenthèses et tout ira bien !
>>> (false && false) || (true && true) true >>> var b = 5; >>> true || (b = 6) // la deuxième partie jamais évaluée ! true >>> b 5 >>> true && (b = 6) // deuxième partie évaluée 6 >>> b 6
Si une opérande non booléene est rencontrée dans une expression, c'est cette dernière qui est renvoyée
>>> true || "something" true >>> true && "something" "something"
Symbole | Description | Exemple |
---|---|---|
== | Egalité avec conversion de type |
>>> 1 == 1 true >>> 1 == 2 false >>> 1 == '1' true |
=== | Egalité sans conversion de type |
>>> 1 === '1' false >>> 1 === 1 true |
Symbole | Description | Exemple |
---|---|---|
!= | Non égalité avec conversion de type | >>> 1 != 1 false >>> 1 != '1' false >>> 1 != '2' true |
!== | Non égalité sans conversion de type | >>> 1 !== 1 false >>> 1 !== '1' true |
NaN n'est égal avec RIEN ! Même pas lui-même !
>>> NaN == NaN false
Undefined est retourné lorsque on accède à une variable qui n'existe pas :
>>> foo foo is not defined >>> typeof foo "undefined"
Ou à une variable qui n'est pas initialisée :
>>> var somevar; >>> somevar >>> typeof somevar "undefined"
null n'est jamais positionné par JavaScript, uniquement par le code :
>>> var somevar = null null >>> somevar null >>> typeof somevar "object"
>>> var i = 1 + undefined; i; NaN >>> var i = 1 + null; i; 1
Cela vient de la conversion implicite de null et undefined dans une expression
>>> 1*undefined NaN >>> 1*null 0
Conversion en booléens : les deux valent false:
>>> !!undefined false >>> !!null false
Conversion vers String :
>>> "" + null "null" >>> "" + undefined "undefined"
Les tableaux sont des objets !
>>> var a = []; >>> typeof a; "object" >>> var a = [1,2,3]; >>> a [1, 2, 3] >>> a[0] 1 >>> a[1] 2
>>> var a = [1,2,3]; >>> a[2] = 'three'; "three" >>> a [1, 2, "three"]
On peut ajouter de nouveaux éléments en utilisant un nouvel index :
>>> a[3] = 'four'; "four" >>> a [1, 2, "three", "four"]
Si on ajoute des éléments avec des indexs numériques non contigus, les valeurs manquantes sont undefined :
>>> var a = [1,2,3]; >>> a[6] = 'new'; "new" >>> a [1, 2, 3, undefined, undefined, undefined, "new"]
On supprime des éléments à l'aide de l'opérateur delete.
L'élément n'est pas vraiment supprimé mais sa valeur devient undefined.
La taille du tableau ne change pas.
>>> var a = [1, 2, 3]; >>> delete a[1]; true >>> a [1, undefined, 3]
Un tableau peut contenir n'importe quel type d'éléments, y compris un autre tableau :
>>> var a = [1, "two", false, null, undefined]; >>> a [1, "two", false, null, undefined] >>> a[5] = [1,2,3] [1, 2, 3] >>> a [1, "two", false, null, undefined, [1, 2, 3]]
>>> var a = [[1,2,3],[4,5,6]]; >>> a [[1, 2, 3], [4, 5, 6]] >>> a[0] [1, 2, 3]
Accès à un élément d'un tableau de tableau :
>>> a[0][0] 1 >>> a[1][2] 6
Une String se manipule comme un tableau de caractères :
>>> var s = 'one'; >>> s[0] "o" >>> s[1] "n" >>> s[2] "e"
Les conditions permettent de controller le flux d'exécution,
Les boucles permettent de répéter des blocs d'instructions,
Les mots-clés JavaScript sont : if, switch, while, do-while, for, et for-in.
Bloc de code : un bloc de code contient plusieurs expressions entre { et } :
{ var a = 1; var b = 3; } { var a = 1; var b = 3; var c, d; { c = a + b; // Bloc de code imbriqué dans un autre bloc de code { d = a - b; } } }
var resultat = ''; if (a > 2) { resultat = 'a est plus grand que 2'; }
La conditon peut comprendre :
if (a > 2) { resultat = 'a est plus grand que 2'; } else { resultat = 'a n'est PAS plus grand que 2'; }
if (a > 2 || a < -2) { resultat = "a n'est pas compris entre -2 et 2"; } else if (a === 0 && b === 0) { resultat = 'a et b sont nuls'; } else if (a === b) { resultat = 'a et b sont égaux'; } else { resultat = "J'abandonne"; }
if (a === 1) { if (b === 2) { resultat = 'a vaut 1 et b vaut 2'; } else { resultat = 'a vaut 1 mais b est différent de 2'; } } else { resultat = 'a est différent de 1, je ne sais pas pour b'; }
On peut tester avec if(variable)... :
>>> var resultat = ''; >>> if (unevariable){resultat = 'oui';} unevariable is not defined >>> resultat; ""
On peut faire plus propre avec l'opérateur typeof :
>>> if (typeof unevariable !== "undefined"){resultat = 'oui';} >>> resultat; ""
typeof renvoie toujours une String
>>> unevariable = 123; >>> if (typeof unevariable !== "undefined"){resultat = 'oui';} >>> resultat; "oui"
var resultat = (a === 1) ? "a vaut 1" : "a est différent de 1";
Est équivalent à :
var a = 1; var resultat = ''; if (a === 1) { resultat = "a vaut 1"; } else { resultat = "a est différent de 1"; }
Remplace un if avec plusieurs else...
var a = '1'; var resultat = ''; switch (a) { case 1: resultat = 'Nombre 1'; break; case '1': resultat = 'String 1'; // Résultat pour cet exemple break; default: resultat = 'Je ne sais pas'; break; } resultat;
While... (boucles "tant que...")
var i = 0; while (i < 10) { i++; }
Do... While (boucles "jusqu'à"...)
var i = 0; do { i++; } while (i < 10)
For (boucle "pour"...)
var punition = ''; for (var i = 0; i < 100; i++) { punition += 'Je ne copierai plus sur mon voisin,\n'; }
for (var i = 0, punition = ''; i < 100; i++) { punition += 'Je ne copierai plus sur mon voisin,\n'; }
var res = '\n'; for(var i = 0; i < 4; i++) { for(var j = 0; j < 10; j++) { res += '* '; } res+= '\n'; }Affiche :
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Ces boucles servent à itérer sur les éléments d'un tableau (ou d'un objet, nous verrons cela plus tard)
var a = ['a', 'b', 'c', 'x']; var result = '\n'; for (var i in a) { result += 'index: ' + i + ', value: ' + a[i] + '\n'; }
Résultat :
index: 0, value: a index: 1, value: b index: 2, value: c index: 3, value: x
Similaires à Java : à l'aide de // ou de /*......*/
// début de ligne var a = 1; // ailleurs sur une ligne /* Un commentaire sur plusieurs lignes */ var b = 2;
Une fonction permet de regrouper du code, de lui donner un nom et de pouvoir l'exécuter en l'appelant par son nom.
function somme(a, b) { var c = a + b; return c; }
Appel de la fonction :
>>> var result = somme(1, 2); >>> result; 3
Si on omet des paramètres, JavaScript leur donne la valeur undefined :
>>> somme(1) NaN
Si on passe trop de paramètres, certains seront ignorés :
>>> somme(1, 2, 3, 4, 5) 3
Un tableau de nom arguments est créé automatiquement dans chaque fonction,
Il contient l'ensemble des paramètres d'appel de la fonction :
>>> function f() { return arguments; } >>> f(); [] >>> f( 1, 2, 3, 4, true, 'ninja'); [1, 2, 3, 4, true, "ninja"]
function sommeAmelioree() { var i, res = 0; var nombreDeParametres = arguments.length; for (i = 0; i < nombreDeParametres; i++) { res += arguments[i]; } return res; }
>>> sommeAmelioree(1, 1, 1); 3 >>> sommeAmelioree(1, 2, 3, 4); 10
Il existe un certain nombre de fonctions prédéfinies en JavaScript
Conversion en entier
>>> parseInt('123') 123 >>> parseInt('abc123') NaN >>> parseInt('1abc23') // attention ! 1 >>> parseInt('123abc') // attention ! 123
Note : il est possible de passer la base en second paramètre...10, 16 ou 8.
Conversion en flottant
>>> parseFloat('123') 123 >>> parseFloat('1.23') 1.23 >>> parseFloat('1.23abc.00') 1.23 >>> parseFloat('a.bc1.23') NaN >>> parseFloat('123e-2') 1.23 >>> parseFloat('123e2') 12300 >>> parseInt('1e10') 1
Permet de tester si une valeur est NaN
>>> isNaN(NaN) true >>> isNaN(123) false >>> isNaN(1.23) false >>> isNaN(parseInt('abc123')) true
Vérifie si le paramètre est différent de Infinity ou de NaN
>>> isFinite(Infinity) false >>> isFinite(-Infinity) false >>> isFinite(12) true >>> isFinite(1e308) true >>> isFinite(1e309) // trop grand ! false
Plus grand nombre en JavaScript = 1.7976931348623157e+308 !
Ces fonctions permettent d'échapper certains caractères dans un URI
encodeURI() et son inverse decodeURI() pour les espaces, accents, etc.
>>> var url = 'http://www.packtpub.com/scr ipt.php?q=this and that'; >>> encodeURI(url); "http://www.packtpub.com/scr%20ipt.php?q=this%20and%20that"
encodeURIComponent() et decodeURIComponent() pour les :// etc.
>>> encodeURIComponent(url); "http%3A%2F%2Fwww.packtpub.com%2Fscr%20ipt.php%3Fq%3Dthis% 20and%20that"
Ces fonctions remplacent escape() et unescape() qui sont deprecated.
eval() : évaluer du JavaScript passé en paramètre :
>>> eval('var i = 2;') >>> i 2
Attention avec eval() :
Fenêtre de dialogue dans le navigateur avec un message.
alert("hello!")
Bloque le thread de gestion de la GUI du browser. Eviter avec Ajax ! Utiliser la console de debug JavaScript à la place !
JavaScript est très particulier, bien noter ces points :
var global = 1;
function f() {
var local = 2;
global++;
return global;
}
>>> f();
2
>>> f();
3
>>> local
local is not defined
Une variable non définie avec var est automatiquement considérée comme globale !
Lors de la définition de la fonction, local n'existe pas,
Lors du premier appel elle est définie en global, ensuite elle existe... Toujours déclarer avec var !
var a = 123; function f() { alert(a); var a = 1; alert(a); } f();
Le premier alert() affiche Undefined et pas 123 !
En effet, le fait qu'une variable a locale soit définie dans la fonction, même après le alert(), cache le fait qu'il existe un a global, comme le a local n'est pas encore initialisé et déclaré, cela provoque un Undefined !
Il s'agit d'un concept très important ! Ces deux écritures sont équivalentes :
function f(){return 1;} var f = function(){return 1;} // déclaration littérale >>> typeof f "function"
Oui, function est un type de donnée et f une variable de ce type.
Si f est une variable de type fonction on peut exécuter son code an ajoutant (...); à son nom.
>>> var somme = function(a, b) {return a + b;} >>> var addition = somme; >>> delete somme true >>> typeof somme; "undefined" >>> typeof addition; "function" >>> addition(1, 2); 3
Puisque une variable peut être une fonction, on appliquera les mêmes règles de nommage (débute par un caractère, peut contenir chiffres et underscore).
On peut écrire du code en dehors de fonctions :
>>> "test"; [1,2,3]; undefined; null; 1;
On peut aussi définir des fonctions sans nom :
>>> function(a){return a;}
Intérêt : on peut les passer en paramètres à la manière des écouteurs Java.
En JavaScript ces écouteurs s'appellent des callbacks et ils sont omniprésents dans les applications web.
function invoke_and_add(a, b){ return a() + b(); // les paramètres sont des fonctions ! } function one() { return 1; } function two() { return 2; } >>> invoke_and_add(one, two); // deux fonctions en paramètres ! 3 >>> invoke_and_add(function(){return 1;}, function(){return 2;}); 3
Le dernier exemple utilise des fonctions de callback anonymes (sans noms) !
Etape 1 : définissons deux fonctions :
function multiplieParDeux(a, b, c) { var i, ar = []; for(i = 0; i < 3; i++) { ar[i] = arguments[i] * 2; } return ar; } function ajouteUn(a) { return a + 1; } >>> multiplyByTwo(1, 2, 3); // renvoie un tableau [2, 4, 6] >>> addOne(100) 101
>>> var myarr = []; >>> myarr = multiplieParDeux(10, 20, 30); [20, 40, 60] // On ajoute un à chaque élément maintenant : >>> for (var i = 0; i < 3; i++) {myarr[i] = ajouteUn(myarr[i]);} >>> myarr [21, 41, 61]
On voudrait tout faire dans la même fonction, mais en pouvant choisir le type d'opération qu'on fait après avoir multiplié tous les éléments par 2 !
function multiplieParDeux(a, b, c, callback) { var i, ar = []; for(i = 0; i < 3; i++) { ar[i] = callback(arguments[i] * 2); } return ar; } >>> myarr = multiplieParDeux(1, 2, 3, ajouteUn); [3, 5, 7] >>> myarr = multiplieParDeux(1, 2, 3, function(a){return a + 1}); [3, 5, 7] >>> myarr = multiplieParDeux(1, 2, 3, function(a){return a + 2}); [4, 6, 8]
Attention à la syntaxe !
( function(){ alert('boo'); } )();
( function(nom){ alert('Hello ' + nom + '!'); } )('Michel');
Utile pour une initialisations, puisqu'on ne peut les appeler qu'une fois avec des paramètres prédéfinis.
Evite l'utilisation de variables globales.
Présenté ici car utilisé par certaines librairies, par des closures (étudiées plus loin)...
Font partie des horreurs de JavaScript qui font hurler les puristes. Cool donc ;-)
function a(param1) { function b(param2) { return param2 * 2; }; return 'Le résultat est ' + b(param1); }; // Peut s'écrire aussi en forme littérale var a = function(param1) { var b = function(param2) { return theinput * 2; }; return 'Le résultat est ' + b(param1); }; >>> a(8); "Le résultat est 16" >>> b(2); b is not defined
Permet de n'exposer que quelques fonctions, les autres sont "cachées"
Evite les collisions de noms
Très utile quand on fera du javaScript orienté objet (on pourra écrire a.b(); !), une fonction interne sera considérée comme une méthode !
Les fonctions étant une donnée comme une autre, elle peut être une valeur de retour :
function a() { alert('A!'); return function(){ alert('B!'); }; }>>> var f = a(); >>> f(); // fera pparaitre un popup avec 'B' ! >>> a()(); // fait la même chose !
a() invoque la fonction a, et a()() invoque la fonction retournée par a()
var a = function() { function someSetup(){ var setup = 'done'; } function actualWork() { alert('Worky-worky'); } someSetup(); return actualWork; }();
Fonction auto invoquée ! a recevra le résultat !
La fonction appelle someSetup() qui peut effectuer des inits ou des tests, par exemple tester dans quel navigateur elle s'exécute...
Elle revoie finalement une fonction (actualWork)... c'est cette valeur que recevra a,
Si on appelle a(); c'est actualWork() qui sera appelée !
Pas de portée par "bloc" mais par "fonction" !
>>> var a = 1; function f(){var b = 1; return a;} >>> f(); 1 >>> b b is not defined
Dans f() a et b sont visibles,
En dehors de f() seul a est visible.
var a = 1; function f(){ var b = 1; function n() { var c = 3; } }
n() est interne à f(),
n() voit les variables de sa portée et aussi celle de son parent. Elle voit donc c, mais aussi b et a.
On parle de "chaîne de portée" ou en anglais "scope chain".
>>> function f1(){var a = 1; f2();}
>>> function f2(){return a;}
>>> f1();
a is not defined
Dans cet exemple, f2() ne voit que son scope et le scope global, a n'est pas définie dedans.
Pourtant lors de l'appel de f2() par f1(), a est bien définie.
Une portée/scope: ensemble de "chemins" dans lesquels des données seront visibles
Définis à la création, non modifiables, mais on peut ajouter/enlever des données dans ces chemins à l'exécution.
>>> function f1(){var a = 1; return f2();} >>> function f2(){return a;} >>> f1(); a is not defined >>> var a = 5; >>> f1(); 5 >>> a = 55; >>> f1(); 55 >>> delete a; true >>> f1(); a is not defined
f2() est dans le scope de f1(), mais on peut modifier la valeur de f2 ou la supprimer.
>>> delete f2; true >>> f1() f2 is not defined >>> var f2 = function(){return a * 2;} >>> var a = 5; 5 >>> f1(); 10
Bon, mais et les closures ? Et bien elles servent à "casser" la chaine des portées, la "scope chain" !
Imaginons le "global scope" comme l'univers. Il est visible par tous !
Il contient des variables et des fonctions (les a1, a2) et des fonctions (F)
Les fonctions ont leur propre scope avec variables et fonctions
si F() contient N()...Le point a est dans le scope global, b dans le scope de F, c dans le scope de N, etc.
De a on ne peut voir b, mais de c on peut voir b, donc de N on peut voir b.
... mais sans le sortir réellement !
N est au même endoit que a maintenant,
Il voit encore le scope de F donc il voit b, alors que a ne le voit pas !
Deux possibilités :
Regardons quelques exemples ensembles...
function f(){ var b = "b"; return function(){ return b; } } >>> b b is not defined >>> var n = f(); >>> n(); "b"
La fonction retournée est similaire à la fonction N des transparents précédents.
var n; function f(){ var b = "b"; n = function(){ // pas de var ! return b; } } >>> f(); >>> n(); "b"
L'appel de f() a défini une nouvelle variable n dans le scope global. Cette variable est une fonction qui voit b.
function f(arg) { var n = function(){ return arg; }; arg++; return n; } >>> var resultat = f(123); >>> resultat(); 124
arg++ est appelé après la définition de n, pourtant l'appel de resultat() donne bien la valeur à jour incrémentée.
Ceci montre bien que les fonctions sont liées à un scope et pas à des valeurs de variables. Lorsque les variables changent dans le scope, ce sont toujours les valeurs à jour qui sont utilisées.
C'est celui de cet exemple simple dans le tutorial HTML5 de M.Buffa
function f() { var a = []; var i; for(i = 0; i < 3; i++) { a[i] = function(){ return i; } } return a; }
Que donne l'exécution de cette fonction ?
function f() { var a = []; var i; for(i = 0; i < 3; i++) { a[i] = function(){ return i; } } return a; } >>> var a = f(); >>> a[0]() 3 >>> a[1]() 3 >>> a[2]() 3
Reprenons tranquillement le code en gardant à l'esprit ce que nous venons d'apprendre...
function f() { var a = []; var i; for(i = 0; i < 3; i++) { a[i] = (function(x){ return function(){ return x; } })(i); } return a; } >>> var a = f(); >>> a[0](); 0 >>> a[1](); 1 >>> a[2](); 2
On met dans a[i] une fonction auto-exécutée :
a[i] = (function(x){ return function(){ return x; } })(i);
Cette fonction prend comme argument i, qui devient le paramètre x, local à la fonction,
a[0] reçoit donc une fonction qui a pour paramètre 0, a[1] une fonction qui a pour paramètre 1, etc.
function f() { function makeClosure(x) { return function(){ return x; } } var a = []; var i; for(i = 0; i < 3; i++) { a[i] = makeClosure(i); } return a; }
Ca marche ou pas ?
function setup(x) { var i = 0; return function(){ return x[i++]; }; } >>> var next = setup(['a', 'b', 'c']); >>> next(); "a" >>> next(); "b" >>> next(); "c"