Cet article présente principalement les fermetures JavaScript. Les fermetures sont une difficulté et une fonctionnalité du langage JavaScript. De nombreuses applications avancées s'appuient sur des fermetures pour implémenter des
fonctions comme valeurs de retour
De plus. Pour accepter des fonctions comme paramètres, les fonctions d'ordre supérieur peuvent également renvoyer des fonctions comme valeurs de résultat.
Implémentons une sommation de Array
. Normalement, la fonction de sommation est définie comme ceci :
function sum(arr) { return arr.reduce(function (x, y) { return x + y; }); } sum([1, 2, 3, 4, 5]); // 15
Cependant, si vous n'avez pas besoin de faire la somme immédiatement, mais dans le code suivant, que devrions-nous faire si nous le calculons à nouveau si nécessaire ? Au lieu de renvoyer le résultat de la sommation, vous pouvez renvoyer la fonction de sommation !
function lazy_sum(arr) { var sum = function () { return arr.reduce(function (x, y) { return x + y; }); } return sum; }
Quand on appelle lazy_sum()
, ce qui est renvoyé n'est pas le résultat de la sommation, mais la fonction de sommation :
var f = lazy_sum([1, 2, 3, 4, 5]); // function sum()
Le résultat de la somme est effectivement calculé lorsque la fonction f est appelée :
f(); // 15
Dans ce Dans l'exemple, on définit la fonction lazy_sum
dans la fonction sum
, et la fonction interne sum
peut faire référence aux paramètres et variables locales de la fonction externe lazy_sum
, lorsque lazy_sum
renvoie la fonction sum
, les paramètres et variables pertinents sont enregistrés dans la fonction renvoyée. Cette structure de programme appelée "Closure" a une grande puissance.
Veuillez noter que lorsque nous appelons lazy_sum()
, chaque appel renverra une nouvelle fonction, même si les mêmes paramètres sont transmis :
var f1 = lazy_sum([1, 2, 3, 4, 5]); var f2 = lazy_sum([1, 2, 3, 4, 5]); f1 === f2; // false
f1()
et f2()
n'ont aucune influence l'un sur l'autre.
Fermeture
Notez que la fonction renvoyée fait référence à la variable locale arr
à l'intérieur de sa définition, donc lorsqu'une fonction renvoie Après une fonction, ses variables locales internes sont également référencées par la nouvelle fonction. Par conséquent, les fermetures sont faciles à utiliser mais pas faciles à implémenter.
Un autre problème à noter est que la fonction renvoyée n'est pas exécutée immédiatement, mais n'est exécutée que lorsque f() est appelée. Regardons un exemple :
function count() { var arr = []; for (var i=1; i<=3; i++) { arr.push(function () { return i * i; }); } return arr; } var results = count(); var f1 = results[0]; var f2 = results[1]; var f3 = results[2];
Dans l'exemple ci-dessus, chaque fois qu'il boucle, une nouvelle fonction est créée, puis la fonction créée est All trois fonctions sont ajoutées à un Array
et renvoyées.
Vous pourriez penser que le résultat de l'appel de f1()
, f2()
et f3()
devrait être 1
, 4
, 9
, mais le résultat réel est :
f1(); // 16 f2(); // 16 f3(); // 16
Tous 16
! La raison en est que la fonction renvoyée fait référence à la variable i
, mais elle n'est pas exécutée immédiatement. Au moment où les trois fonctions reviennent, la variable i à laquelle elles font référence est devenue 4
, donc le résultat final est 16
.
Une chose à garder à l'esprit lors du retour d'une fermeture est la suivante : la fonction de retour ne doit faire référence à aucune variable de boucle ou à des variables qui changeront par la suite.
Et si vous devez référencer une variable de boucle ? La méthode consiste à créer une autre fonction et à utiliser le paramètre de la fonction pour lier la valeur actuelle de la variable de boucle. Quelle que soit la façon dont la variable de boucle change par la suite, la valeur est liée au paramètre de fonction <. 🎜> reste inchangé :
function count() { var arr = []; for (var i=1; i<=3; i++) { arr.push((function (n) { return function () { return n * n; } })(i)); } return arr; } var results = count(); var f1 = results[0]; var f2 = results[1]; var f3 = results[2]; f1(); // 1 f2(); // 4 f3(); // 9
et l'exécuter immédiatement" est utilisée. ici :
(function (x) { return x * x; })(3); // 9
function (x) { return x * x } (3);
, une erreur SyntaxError sera signalée, donc la définition entière de la fonction doit être mise entre parenthèses :
(function (x) { return x * x }) (3);
(function (x) { return x * x; })(3);
Bien sûr que non ! Les fermetures sont très puissantes. Par exemple :
Dans les langages de programmation orientés objet, tels que Java et C++, pour encapsuler une variable privée dans un objet, vous pouvez utiliser private pour modifier une variable membre.
Dans un langage qui n'a pas de mécanisme
class
'use strict'; function create_counter(initial) { var x = initial || 0; return { inc: function () { x += 1; return x; } } }
var c1 = create_counter(); c1.inc(); // 1 c1.inc(); // 2 c1.inc(); // 3 var c2 = create_counter(10); c2.inc(); // 11 c2.inc(); // 12 c2.inc(); // 13
n'est pas du tout accessible à partir du code externe. En d’autres termes, une fermeture est une fonction qui porte un état, et son état peut être complètement caché au monde extérieur. x
x
闭包还可以把多参数的函数变成单参数的函数。例如,要计算xy可以用Math.pow(x, y)
函数,不过考虑到经常计算x2或x3,我们可以利用闭包创建新的函数pow2
和pow3
:
function make_pow(n) { return function (x) { return Math.pow(x, n); } } // 创建两个新函数: var pow2 = make_pow(2); var pow3 = make_pow(3); pow2(5); // 25 pow3(7); // 343
脑洞大开
很久很久以前,有个叫阿隆佐·邱奇的帅哥,发现只需要用函数,就可以用计算机实现运算,而不需要0、1、2、3
这些数字和+、-、*、/
这些符号。
JavaScript支持函数,所以可以用JavaScript用函数来写这些计算。来试试:
'use strict'; // 定义数字0: var zero = function (f) { return function (x) { return x; } }; // 定义数字1: var one = function (f) { return function (x) { return f(x); } }; // 定义加法: function add(n, m) { return function (f) { return function (x) { return m(f)(n(f)(x)); } } }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!