Heim  >  Artikel  >  Web-Frontend  >  Verschlüsse in JavaScript

Verschlüsse in JavaScript

韦小宝
韦小宝Original
2018-03-07 14:08:281199Durchsuche

Jeder kann den Abschluss in nur ein oder zwei Sätzen aufsagen. Aber eine Abschlussfrage ist die Art von Frage, mit der Anfänger in acht von zehn Interviews konfrontiert werden. Wenn sie sie nicht beantworten können, erhalten sie einen Vorschlag, und wenn sie sie beantworten können, erhalten sie keine Punkte. Um zu verhindern, dass unsere Front-End-Entwicklung anfängt und aufgibt, möchte ich darüber sprechen, was meiner Meinung nach der Abschluss in JS ist.

Was ist ein Abschluss?

Ein Abschluss erstellt einen lexikalischen Bereich, in dem auf die Variablen verwiesen wird Dieser lexikalische Bereich ist außerhalb der Domäne frei zugänglich und stellt eine Kombination aus einer Funktion und der lexikalischen Umgebung dar, in der die Funktion deklariert ist.

Man kann auch sagen, dass ein Abschluss eine Funktion ist, die auf eine freie Funktion verweist Diese freie Variable existiert zusammen mit der Funktion, auch wenn sie getrennt ist. Die Umgebung, in der sie erstellt wurde. Man sieht also oft, dass ein Abschluss eine an einen Kontext gebundene Funktion ist, und das ist wahrscheinlich auch die Bedeutung. Sobald Sie es verstanden haben, werden Sie das Gefühl haben, dass es eigentlich eine sehr einfache Sache ist und nicht sehr tiefgreifend.

In der folgenden Einleitung bevorzuge ich die Erklärung, dass der Abschluss eine Kombination aus einer Funktion und der lexikalischen Umgebung ist, in der die Funktion deklariert wird, daher werde ich auch auf der Grundlage dieser Erklärung näher darauf eingehen.

Closure ist eigentlich ein Konzept in der Informatik und nicht nur auf JS beschränkt. Das Konzept der Schließung tauchte in den 1960er Jahren auf und die früheste Programmiersprache zur Implementierung der Schließung war Scheme. (Fragen Sie mich nicht, was Scheme ist, ich weiß nicht, ob Sie mich fragen. Dieser Absatz wurde aus dem Wiki kopiert.) Danach wurden Abschlüsse häufig in funktionalen Programmiersprachen verwendet.

Verschlüsse in JS

Jetzt habe ich einen Trick, um einen Verschluss mit bloßen Händen herauszuziehen.

function sayHello(name) {
  let str = `Hello,${name}`;
  function say() {
    console.log(str);
  }
  return say;
}

let myHello = sayHello('abby');
myHello(); // Hello,abby

Der obige Code bildet tatsächlich einen Abschluss. Die in der Funktion sayHello definierte Funktion say und die lexikalische Umgebung, in der sie deklariert ist, bilden einen Abschluss, da sie auf eine in sayHello definierte Variable str verweist Die Funktion say wird zurückgegeben, sodass auf die in der Funktion sayHello definierte Variable str auch außerhalb der Funktion sayHello zugegriffen werden kann, als ob die Funktion say an diese Variable gebunden wäre.

Wenn Sie das sehen, fragen Sie sich vielleicht, warum auf diese Variable immer noch extern zugegriffen werden kann, da in einigen Sprachen allgemein angenommen wird, dass auf die lokalen Variablen einer Funktion nur während der Ausführung der Funktion zugegriffen werden kann. Apropos, ich muss über die Ausführungsumgebung sprechen. Freunde, die nicht viel darüber wissen, lesen vielleicht zuerst meinen Artikel: Ausführungskontext, den Sie nicht kennen. Tatsächlich soll die Ausführungsumgebung von sayHello() zerstört werden, wenn der Code let myHello = sayHello('abby'); ausgeführt wird. Der Grund dafür ist, dass sayHello() eine Funktion zurückgibt Diese Funktion bezieht sich auf die externe Variable str. Wenn sie zerstört wird, wird sie nicht gefunden. Daher befindet sich die Ausführungsumgebung der Funktion sayHello() immer im Speicher, sodass es zu Schließungen kommt, die den Speicher vergrößern Overhead wie Balabala.

Eigentlich sollte der Abschluss hier abgeschlossen sein, aber es kann viele Dinge geben, die Sie verwirren, also machen wir mit ein paar Beispielen weiter!

Zum Beispiel

Beispiel 1: Verschlüsse müssen nicht unbedingt eine Funktion zurückgeben

Obwohl übliche Verschlüsse Pakete alle zurückgeben eine Funktion, aber Abschlüsse müssen nicht unbedingt zurückkehren, um auf eine Variable außerhalb des Gültigkeitsbereichs zuzugreifen. Wir können dies auch auf andere Weise tun, wie zum Beispiel:

let say;
function sayHello(name) {
  let str = `Hello,${name}`;
  say = function() {
    console.log(str);
  }
}
let myHello = sayHello('abby');
say(); // Hello,abby

In diesem Beispiel. say und die lexikalische Umgebung, in der es deklariert wird, bilden tatsächlich einen Abschluss, und sein Bereich enthält einen Verweis auf die in der Funktion sayHello definierte str-Variable, sodass er auch außerhalb des Bereichs, in dem er definiert ist, auf die str-Variable zugreifen kann. Finden Sie einfach die Art der Schließungen heraus.

Aber in JS besteht die häufigste Art, einen Abschluss zu bilden, darin, eine andere Funktion innerhalb einer Funktion zu verschachteln, und die andere Funktion enthält die im übergeordneten Bereich definierten Variablen.

Beispiel 2: Die gleiche aufrufende Funktion generiert die gleiche Abschlussumgebung und alle darin deklarierten Funktionen haben auch Verweise auf die freien Variablen in dieser Umgebung.

Dieser Satz klingt kompliziert, aber eigentlich gebe ich Ihnen ein sehr einfaches Beispiel.

let get, up, down
function setUp() {
  let number = 20
  get = function() {
    console.log(number);
  }
  up = function() {
    number += 3
  }
  down = function() {
    number -=2;
  }
}
setUp();
get(); // 20
up();
down();
get(); // 21

In diesem Beispiel verwenden wir die Funktion setUp, um eine Abschlussumgebung zu generieren. Die drei Funktionen in dieser Umgebung teilen sich den Verweis auf die Zahlenvariable in dieser Umgebung, sodass sie alle auf Zahlenoperationen zugreifen können.

Beispiel 3: Jeder Funktionsaufruf erstellt eine andere Abschlussumgebung.

Lassen Sie uns ein sehr einfaches Beispiel geben.

function newClosure() {
  let array = [1, 2];
  return function(num) {
    array.push(num);
    console.log(`array:${array}`);
  }
}
let myClosure = newClosure();
let yourClosure = newClosure();
myClosure(3); // array:1,2,3
yourClosure(4); // array:1,2,4
myClosure(5); // array:1,2,3,5

Im obigen Beispiel werden die Zuweisungsanweisungen von myClosure und yourClosure, d. h. die newClosure-Funktion, zweimal aufgerufen, wodurch zwei unterschiedliche Abschlussumgebungen erstellt werden, sodass sich die Variablen darin gegenseitig ausschließen.

Beispiel 4: Erstellen eines Abschlusses innerhalb einer Schleife

function newClosure() {
  for(var i = 0; i < 5; i++) {
    setTimeout(function() {
      console.log(i);
      })
  }
}
newClosure(); // 5个5

打印的结果大家也知道是5个5,因为 setTimeout 里面的函数保持对 i 的引用,在setTimeout的回调函数被执行的时候这个循环早已经执行完成,这里我之前在另一篇文章里面做过更深入的介绍:深入浅出Javascript事件循环机制(上)。

这里我要说的是我们如何才能得到我们想要的01234,在这里有两种做法。

一种是 创建一个新的闭包对象,这样每个闭包对象里面的变量就互不影响。例如下面的代码种每次 log(i)都会创建不同的闭包对象,所有的回调函数不会指向同一个环境。

function log(i) {
  return function() {
    console.log(i);
  }
}
function newClosure() {
  for(var i = 0; i < 5; i++) {
    setTimeout(log(i));
  }
}
newClosure(); // 0 1 2 3 4

另一种做法就是使用自执行函数,外部的匿名函数会立即执行,并把 i 作为它的参数,此时函数内 e 变量就拥有了 i 的一个拷贝。当传递给 setTimeout 的匿名函数执行时,它就拥有了对 e 的引用,而这个值是不会被循环改变的。写法如下:

function newClosure() {
  for(var i = 0; i < 5; i++) {
    (function(e) {
      setTimeout(function() {
        console.log(e);
      })
    })(i)  
  }
}
newClosure(); // 0 1 2 3 4

看看,写这么多,多累是不是,还是let省事,所以赶紧拥抱 es6 吧。。。

好了,这次是真的结束了,我所理解的闭包大概就是这样了,如果理解有所偏差,欢迎指出,谁当初不是从颗白菜做起的呢,学习前端的小伙伴们可以看看哦!

关于闭包:

js中作用域与函数闭包实例讲解

Das obige ist der detaillierte Inhalt vonVerschlüsse in JavaScript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn