Maison > interface Web > js tutoriel > le corps du texte

Comment utiliser les fermetures en js ?

零下一度
Libérer: 2017-06-28 13:38:10
original
1556 Les gens l'ont consulté

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
Copier après la connexion

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;
}
Copier après la connexion

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()
Copier après la connexion

Le résultat de la somme est effectivement calculé lorsque la fonction f est appelée :


f(); // 15
Copier après la connexion

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
Copier après la connexion

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];
Copier après la connexion

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
Copier après la connexion

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
Copier après la connexion
Notez que la syntaxe de "créer une fonction anonyme

et l'exécuter immédiatement" est utilisée. ici :


Théoriquement, pour créer une fonction anonyme et l'exécuter immédiatement vous pouvez écrire :
(function (x) {
  return x * x;
})(3); // 9
Copier après la connexion



Cependant, en raison de problèmes d'analyse de la
function (x) { return x * x } (3);
Copier après la connexion
syntaxe JavaScript

, une erreur SyntaxError sera signalée, donc la définition entière de la fonction doit être mise entre parenthèses :


Habituellement, une fonction anonyme exécutée immédiatement peut séparer le corps de la fonction, généralement écrit comme ceci :
(function (x) { return x * x }) (3);
Copier après la connexion



Cela dit, est-il fermé ? Le but du package est-il simplement de renvoyer une fonction puis de retarder son exécution ?
(function (x) {
  return x * x;
})(3);
Copier après la connexion


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

et n'a que des fonctions, une variable privée peut également être encapsulée à l'aide de fermetures. Nous créons un compteur en utilisant JavaScript :

class


Cela fonctionne comme ceci :
&#39;use strict&#39;;

function create_counter(initial) {
  var x = initial || 0;
  return {
    inc: function () {
      x += 1;
      return x;
    }
  }
}
Copier après la connexion



Dans l'objet renvoyé, une fermeture est implémentée, qui porte la variable locale
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
Copier après la connexion
, et la variable

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. xx

闭包还可以把多参数的函数变成单参数的函数。例如,要计算xy可以用Math.pow(x, y)函数,不过考虑到经常计算x2或x3,我们可以利用闭包创建新的函数pow2pow3


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
Copier après la connexion

脑洞大开

很久很久以前,有个叫阿隆佐·邱奇的帅哥,发现只需要用函数,就可以用计算机实现运算,而不需要0、1、2、3这些数字和+、-、*、/这些符号。

JavaScript支持函数,所以可以用JavaScript用函数来写这些计算。来试试:


&#39;use strict&#39;;

// 定义数字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));
    }
  }
}
Copier après la connexion

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal