Heim > Web-Frontend > js-Tutorial > Was ist eine Schließung? Lassen Sie uns über Abschlüsse in JavaScript sprechen und sehen, welche Funktionen sie haben.

Was ist eine Schließung? Lassen Sie uns über Abschlüsse in JavaScript sprechen und sehen, welche Funktionen sie haben.

青灯夜游
Freigeben: 2022-07-08 11:14:54
nach vorne
1738 Leute haben es durchsucht

Was ist Schließung? Sehen Sie, was Schließungen bewirken? Der folgende Artikel befasst sich mit Abschlüssen in JavaScript. Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird für alle hilfreich sein.

Was ist eine Schließung? Lassen Sie uns über Abschlüsse in JavaScript sprechen und sehen, welche Funktionen sie haben.

Im Prozess des Front-End-Lernens werden wir unweigerlich auf viele Probleme stoßen. Deshalb werden wir heute aus der Sicht eines Anfängers über zwei Fragen sprechen:

Was ist ein Abschluss?

Welche Funktionen haben Verschlüsse?

Tatsächlich sind Schließungen überall, wenn wir Javascript lernen, man muss sie nur erkennen und akzeptieren können. Abschlüsse sind kein Werkzeug, für dessen Verwendung das Erlernen einer neuen Syntax oder eines neuen Musters erforderlich ist. Abschlüsse sind eine natürliche Folge des Schreibens von Code, der auf dem lexikalischen Bereich basiert. Beim Schreiben von Code müssen wir selten absichtlich Abschlüsse erstellen.

Ich glaube, dass viele Freunde zu diesem Zeitpunkt bereits in ihrem Herzen murmeln: Was ist dieser lexikalische Bereich, hören Sie mir einfach langsam zu. Mit anderen Worten: Der lexikalische Bereich wird dadurch bestimmt, wo Sie beim Schreiben des Codes Variablen und Bereiche auf Blockebene platzieren, sodass der Bereich (meistens) unverändert bleibt, wenn der lexikalische Analysator den Code verarbeitet. ——„JavaScript-Volumen, das Sie nicht kennen“

Nehmen wir zuerst ein Beispiel

function test(){
   var arr = []
   for(var i=0;i<10;i++){
       arr[i]=function(){
           console.log(i);
       }
   }
   return arr
}

var myArr = test()
// myArr[0]()
// myArr[1]()
// ...

for(var j = 0; j < 10; j++){ 
   myArr[j]()
}
//为了避免繁琐此处使用了第二个循环来调用test函数里第一个循环里函数的打印出十个结果
Nach dem Login kopieren

Lassen Sie uns zuerst diesen Code analysieren: Wenn dieser Code ausgeführt wird, sollten laut Analyse des gesunden Menschenverstandes zehn Zahlen von 0 bis 9 nacheinander ausgegeben werden, die Ausführung der for-Schleife dauert jedoch nicht (vernachlässigbar in Mikrosekunden). Wenn der Funktionstest arr, arr[ zurückgibt. ] Darin sind 10 function(){console.log(i);} Zu diesem Zeitpunkt werden die Funktionen im Array nicht ausgeführt, wenn var myArr = test() die Testfunktion aufruft, da die Ausführungszeit der for-Schleife überschritten ist wird ignoriert, this Zu diesem Zeitpunkt ist i bereits 10, also werden 10 10s gedruckt.

Ich glaube, jetzt wird jemand fragen: Was hat das mit der Schließung zu tun, über die wir sprechen? Wenn wir diesen Code also leicht modifizieren und ihn in einen Akkumulator umwandeln, wie können wir ihn dann implementieren?

Ich glaube, dass es derzeit große Köpfe geben wird, die sagen, dass das nicht so einfach ist?

Ändern Sie die Var-Definition in eine Let-Definition, sodass die erste for-Schleife zu einem Bereich auf Blockebene wird und dann zu einem Akkumulator werden kann. Natürlich gibt es kein Problem,

Aber wir reden heute darüber, wie man einen Akkumulator in ES5 implementiert. Schauen wir uns dann den folgenden Code an:

function test(){
    var arr = []
    for(var i=0;i<10;i++){
        (function(j){
            arr[j]=function(){
                console.log(j);
            }
        })(i)
    }
    return arr
}

var myArr = test()

for(var j = 0; j < 10; j++){ 
    myArr[j]()
}
Nach dem Login kopieren

Aufmerksame Freunde werden auf jeden Fall feststellen, dass dies lediglich den Funktionskörper in der Schleife in eine selbstausführende Funktion ändert, das Ausgabeergebnis jedoch zu diesem Zeitpunkt ist Es werden zehn Zahlen von 0 bis 9 ausgegeben, die Abschlüsse enthalten. Wenn wir mit der Ausführung dieses Codes beginnen, wird die zweite for-Schleife zehnmal aufgerufen. Wenn jede selbstausführende Funktion ausgeführt wird, wird eine selbstausführende Funktion erstellt. Das AO-Objekt der ausführenden Funktion enthält ein Attribut mit dem Namen j im AO-Objekt der selbstausführenden Funktion. Wie üblich sollte das AO-Objekt nach Abschluss der Ausführung zerstört werden [j] () wird ausgeführt, der Attributname j wird im AO-Objekt von arr[j] oben in der Bereichskette gesucht, aber nicht gefunden. Dann suchen wir die Bereichskette nach unten und finden ihn Das AO-Objekt der selbstausführenden Funktion, also wenn die selbstausführende Funktion Wenn die Ausführungsfunktion endet, wird ihr AO-Objekt nicht vom Garbage-Collection-Mechanismus recycelt, andernfalls wird ein Fehler gemeldet, wenn myarr[j] () ist ausgeführt, und zu diesem Zeitpunkt wird ein Abschluss gebildet.

Wenn eine Funktion extern gespeichert wird, wird ein Abschluss generiert. Nehmen wir ein weiteres Beispiel. Wir verwenden zunächst die Vorkompilierung, um diesen Code zu analysieren Deklaration, suchen Sie nach der globalen Variablendeklaration und verwenden Sie die Variablendeklaration als Attributnamen von GO, wobei der Wert undefiniert ist. Suchen Sie für die globale Deklaration die Funktionsdeklaration und verwenden Sie den Funktionsnamen als Attributnamen des GO-Objekts. und weisen Sie den Wert dem Funktionskörper zu. Zu diesem Zeitpunkt sollte es GO{ glob: undefined--->100: a: fa(){} }; Erstellen Sie dann ein AO{ aaa: undefiniert--->123;b: fb(){} } für Funktion a und kompilieren Sie schließlich Funktion b in Funktion a vor, um ein AO{ b: undefiniert-- ->234} zu erstellen. ;Die Reihenfolge der Bereichskette ist zu diesem Zeitpunkt 1. AO-Objekt der Funktion b; 2. AO-Objekt der Funktion a; Wenn wir aaa in Funktion b ausgeben, beginnen wir am Anfang der Bereichskette. Wenn im AO-Objekt der Funktion b kein aaa vorhanden ist, suchen wir entlang der Bereichskette nach unten, um den AO der Funktion a der zweiten Ebene zu finden Das Ziel besteht darin, den Wert von aaa als 123 zu ermitteln und das Ergebnis auszugeben.

如果我们没有从预编译的角度去分析就会认为此时的aaa应该会报错的,当var demo = a()执行时,当a函数执行结束,那么a对应的AO对象应该被销毁了,照常理分析当我们执行demo时作用域链此时应该会创建b的AO对象和GO对象,此时只有b的AO对象,没有a的AO对象,应该不能打印出aaa的值,但是此时aaa的值为123,则说明a的AO对象没有被销毁,那么为什么呢?原因就在于这里创建了闭包,当var demo = a()执行结束之后,垃圾回收机制会来问,a函数老兄,我看你都执行完毕了,你的运行内存是不是可以给我释放了,但是此时a函数只能无奈摇摇头说道,老哥,我也不确定我有没有执行完毕,我执行完创建了一个b,但是b又不归我管,所以我也不确定b有没有被调用,所以我也不确定我有没有执行完毕,垃圾回收机制想了想,既然你都不知道那我就不回收了,要是回收了还没执行完的就该报错了,所以此时a的AO对象就没有被回收。

补充全面一点就是:当一个函数内部的函数被保存到函数外部时,就会产生闭包。

相信通过这两个例子,你已经对闭包有了一个大概的了解,那接下来我们说一下闭包有哪些作用。

闭包的作用

    1. 实现公有变量 例如:累加器(3.js)
    1. 做缓存
    1. 可以实现封装,属性私有化
    1. 模块化开发,防止污染全局变量

我们对闭包的作用也来一个例子(3.js)

 var count = 0
 function add() {
   return count++
 }
 console.log(add());
 console.log(add());
 console.log(add());
Nach dem Login kopieren

这是一段比较普通的累加的代码,但是如果我们在实习甚至是工作的时,公司要求你把累加器封装成一个模块化的代码,那么
此时,为了模块化我们尽可能避免定义全局变量,但是不定义全局变量我们如何实现呢,此时我们就可以用到闭包了;

function add() {
    var count = 0
    function a() {
      ++count
      console.log(count);
    }
    return a
  }
  var res = add()
  res()
  res()
  
  //add函数结束之后,add的AO对象没有被销毁,因为add函数执行完了之后,返回的a不知道是否被调用就形成了闭包,这样
  就能使得不使用全局变量也能封装成一个模块化的累加器。
Nach dem Login kopieren

结语

那么关于闭包以及闭包的作用相关的一些个人见解就是这些,目前对于闭包也只是一些浅显的了解,后期学习之后完善过后会出后续关于闭包的相关文章,感谢您的观看,欢迎批评斧正,一起共同进步。

【相关推荐:javascript视频教程web前端

Das obige ist der detaillierte Inhalt vonWas ist eine Schließung? Lassen Sie uns über Abschlüsse in JavaScript sprechen und sehen, welche Funktionen sie haben.. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:juejin.cn
Erklärung dieser Website
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
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage