Affichage des articles dont le libellé est let. Afficher tous les articles
Affichage des articles dont le libellé est let. Afficher tous les articles

Closure : one more !

Article

Vous pouvez commencer par lire un article général sur les closures : Article sur les closures

Code

Nous pouvons examiner trois exemples de code et le résultat dans le débogueur :

http://jsbin.com/xuqika/2/edit?html,js,console,output

function f(){
console.log(C);
}
f();
let C = "c";

A l'appel de la fonction C est inconnue !

{
let U = "je suis oubliée par la closure";
function f(){
   console.log(C);
}
let C = "c";
} // bloc
f();

A l'appel de la fonction C est connue. Or le bloc n'est plus accessible (on ne pourrait afficher U en dehors). Cela semble magique ... 

http://jsbin.com/xuqika/3/edit?html,js,console,output

La "closure" est intelligente (elle ne garde vraiment que les variables utiles)
http://jsbin.com/xuqika/3/edit?html,js,console


Historiquement, avant l'arrivée des blocs, nous pouvions générer une closure de la façon suivante :

function A() {
  let a = " a ";
  function B() {
    console.log (a);
  }
  return B;
}

let closure = A();
closure();

Le fermeture (closure) est constituée de la fonction B et de son environnement. Ainsi, l'exécution de la fonction closure permet d'atteindre la variable a.

Le comportement est surprenant car : 
When you declare a variable in a function, you can access this variable only within the function. You can't get this variable once you get out of it.

Voici la vue du débogger.



JS Bin on jsbin.com

var dans les boucles !



let tab = ["a","b","c"];

var printI = function(){
     console.log(tab[i]);
};

for (var i=0; i<tab.length;i++){
    setInterval(printI, 1000*(i+1));
}
let tab = ["a","b","c"];
var i; // i sera égal à  3 lors des appels
var printI = function(){
     console.log(tab[i]);
};

for (i=0; i<tab.length;i++){
    setInterval(printI, 1000*(i+1));
}

for (var i=0; i<tab.length;i++){
     setTimeout(function(){
       console.log("in call back " + i);
     }, 3000*(i+1));
}

Correction avec closure

"use strict";

var _loop = function _loop(i) {
    setTimeout(function () {
        console.log("in call back " + tab[i]);
    }, 1000 * (i + 1));
};

for (var i = 0; i < tab.length; i++) {
    _loop(i);
}


Correction  : 

for (let i=0; i<tab.length;i++){
    setTimeout(function(){
        console.log("in call back " + tab[i]);
    }, 1000*(i+1));
}



boucle let/var

const arr = [];
for (var i=0; i < 3; i++) {
    arr.push(() => i);
}

console.log(arr.map(f => f()));

const arrL = [];
for (let i=0; i < 3; i++) {
    arrL.push(() => i);
}

console.log(arrL.map(f => f()));
JS Bin on jsbin.com

Hoisting ?

D'une certaine façon let fonctionne comme var, la seule différence dans cette analogie est que let fonctionne avec les portées de bloc et var avec les portées des fonctions.

L’apparition de Let pour déclarer les variables a mis en avant le terme de Hoisting.

Hoisting en action !

var et let en action

Cas des boucles : 


Voici une illustration simple comparant les codes

for ( var i=0 ; i < 3 ; i++ ) {
  toto ( i )  // Chaque i pointe sur le même valeur
}
for ( let i=0 ; i < 3 ; i++ ) {
  toto ( i ) // Chaque i a une valeur différente
}


JS Bin on jsbin.com

Exemple

Voici un premier exemple montrant l'impact de l'utilisation de let !

JS Bin on jsbin.com

L'utilisation de var dans la boucle, nous oblige à mettre en place une "seconde" closure

JS Bin on jsbin.com

Article pour aller plus loin

Autre exemple

cas du let !

var arrayAffichage = [];
for (let i = 0; i< 3; i++) {
  arrayAffichage[i] = function toto() {
    console.log(i);
  };
}

arrayAffichage[0]();

let on jsbin.com

 cas du var ! 

/*
Une "closure" permet de référencer une variable qui existe dans la fonction parent. Ici, elle ne fournit pas la valeur de la variable au moment de sa création, mais fourni la dernière des valeurs dans la fonction parent.
*/

var arrayAffichage = [];
 for (var i = 0; i< 3; i++) {
  arrayAffichage[i] = affiche;}

function affiche() {
    console.log(i);
  }

arrayAffichage[0]();

Tester ce code ! /* solution une closure bis  : Création d'une référence non partagée'*/

var arrayClosureAffichage = [];
 for (var i = 0; i< 3; i++) {
  arrayClosureAffichage[i] = afficheClosure(i);
}

function afficheClosure(i) {
  return function(){
    console.log(i);    
  };
}

arrayClosureAffichage[0]();

/* Autre soution : itérateur forEach */
var arrayAffichages = [afficheForEach,afficheForEach,afficheForEach];

arrayAffichages.forEach(function(f,i){
  f(i);
});

function afficheForEach(i) {
    console.log(i);
}


JS Bin on jsbin.com


Autre exemple montrant l'importance de l'utilisation de let versus var !

rempcar var/let dans le code