La fermeture de Javascript?

Méthode n ° 1

function transform(ar) { var alStr = []; for(var i=0; i<ar.length; i++) { alStr[i] = (function(v) { return (function() { return v; }); }(ar[i])); } return alStr; } var a = ["a", 24, { foo: "bar" }]; var b = transform(a); a[1]; b[1](); 

Méthode n ° 2

 function transform(ar) { var alStr = []; for(var a in ar) { var O = function() { return a; } alStr.push(O); } return alStr; } var a = ["a", 24, { foo: "bar" }]; var b = transform(a); a[1]; b[1](); 

Les méthodes mentionnées ci-dessus sont utilisées pour convertir des objets de tableau en fonctions individuelles qui, lors de l'exécution, renvoient l'objet de tableau spécifique. Vous voulez savoir pourquoi la méthode # 1 fonctionne et la méthode n ° 2 n'est pas.

Dans la méthode n ° 2, il existe deux problèmes:

  1. Vous renvoyez le nom de la clé, a , plutôt que la valeur du tableau, ar[a] . C'est plutôt que de return a; Vous voulez return ar[a]; .

  2. La fonction se référera toujours à la dernière valeur en boucle car elle fait référence au même objet de portée. Pour créer un nouvel objet de portée, vous aurez besoin d'une fermeture, d'un bloc ou d'une fonction reliée.

Avec une fermeture:

 for(var a in ar) { var O = (function(val) { return function() { return val; } })(ar[a]); alStr.push(O); } 

Avec un bloc with :

 for(var a in ar) { with({val: ar[a]}) { alStr.push(function() { return val; }); } } 

Avec une fonction liée:

 for(var a in ar) { var O = function(x) { return x; }; alStr.push(O.bind(null, arr[a])); } 

Peter Olson a raison. Cependant, la manière la plus moderne (correcte?) De faire ceci est en utilisant function.bind(obj, val) . Introduit quelque peu récemment, function.bind vous permet de passer des variables par valeur et dans certains contextes. Lire la suite ici .

Donc, vous pourriez écrire quelque chose comme ceci:

 function transform(ar) { var alStr = []; var O = function(x) { return x } for(var a in ar) { alStr.push(O.bind(null, ar[a])); } return alStr; } var a = ["a", 24, 12345]; var b = transform(a); console.log(a[2]); b[2](); 

Il s'agit d'un paradigme plus correct en raison du fait que l'ouverture de fermetures a des implications très claires. L'utilisation de bind, cependant, tend à être une approche fonctionnelle à utiliser spécifiquement lorsque l'appel de la fonction (dans des contextes particuliers ou avec des stipulations particulières).

L'utilisation d'un bloc comporte également des inconvénients (il y a plein de questions à ce sujet).

Bonus : si vous vouliez que b représente également les modifications ultérieures du tableau, cette solution résout ce problème:

 function transform(ar) { var alStr = []; var O = function(x) { return ar[x] } for(var a in ar) { alStr.push(O.bind(null, a)); } return alStr; } var a = ["a", 24, 12345]; var b = transform(a); console.log(a[2]); console.log(b[2]()); console.log("*********"); a[2] = "new value!"; console.log(a[2]); console.log(b[2]());