Heim  >  Artikel  >  Web-Frontend  >  Ein genauerer Blick auf Abschlüsse in JavaScript

Ein genauerer Blick auf Abschlüsse in JavaScript

PHPz
PHPznach vorne
2016-05-16 16:32:511954Durchsuche

In diesem Artikel werden Ihnen Schließungen in JavaScript vorgestellt. Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird für alle hilfreich sein.

Ein genauerer Blick auf Abschlüsse in JavaScript

Abschluss – ein sehr wichtiges, aber schwer zu verstehendes Konzept. Das Verstehen des Abschlusses kann gewissermaßen als Wiedergeburt angesehen werden – „Sie kennen Js nicht“
Auch wenn jeder es satt hat, Schließungen zu sehen, möchte ich dennoch versuchen, es zusammenzufassen! ! !

1. Was ist ein Abschluss?

Wenn wir auf ein Problem stoßen, fragen wir uns zunächst, warum Versuchen Sie zu antworten:

  • Ein Abschluss ist eine Unterfunktion innerhalb einer Funktion - 等于没说

  • Sie tritt auf, wenn sich eine Funktion merken kann und Zugriff auf den lexikalischen Bereich, in dem sie sich befindet. Abschluss, auch wenn die Funktion außerhalb des aktuellen lexikalischen Bereichs ausgeführt wird. ——靠谱

  • Ein Abschluss ist eine Funktion, die die internen Variablen anderer Funktionen lesen kann. Sie ist im Wesentlichen eine Brücke zwischen den internen und externen Links der Funktion——靠谱

  • Eine Funktion und ein Verweis auf ihren umgebenden Zustand (lexikalische Umgebung) werden zu einem Abschluss gebündelt - 很靠谱

Lasst uns Versuchen Sie, mithilfe von Code die obigen Antworten zu beschreiben und finden Sie heraus, welche Ihnen Favoriten~

1.1 Der Abschluss ist eine Unterfunktion innerhalb einer Funktion

Schauen Sie sich zunächst diesen Code an:

function foo(params) {
    var a = '余光';

    function bar() {
        console.log(a);
    }
    bar()
}

foo(); // 余光

Basierend auf den Suchregeln des lexikalischen Bereichs kann bar函数 die Variable a erfolgreich drucken, und es ist auch eine Unterfunktion von foo, aber Streng genommen ist dies nicht der Fall. Das Konzept der Schließung ist nicht klar ausgedrückt. Genauer gesagt können verschachtelte Funktionen auf Variablen zugreifen, die in einem großen äußeren Bereich deklariert sind.

1.2 Der Abschluss ist eine Funktion, die die internen Variablen anderer Funktionen lesen kann. Sie ist im Wesentlichen eine Brücke zwischen der internen Funktion und der externen Verknüpfung der Funktion

Schauen Sie im folgenden Beispiel: Die Ergebnisse von

function foo(params) {
    var a = '余光';

    function bar() {
        console.log(a);
    }
    return bar;
}

var res = foo();
res(); // 余光
sind konsistent, da

die res-Referenz ist, die beim Ausführen der foo-Funktion zurückgegeben wird und die Bar-Funktion ihre lexikalische Umgebung speichern kann. bar

1.3 Eine Funktion und ein Verweis auf ihren umgebenden Zustand (lexikalische Umgebung) werden zu einem Abschluss gebündelt

Sehen wir uns den folgenden Code an:

var name = '余光';

function foo() {
  console.log(name); // 余光 
}

foo(); //余光
Der Kontext von foo wird statisch gespeichert und beim Erstellen der Funktion gespeichert. Lassen Sie es uns unten überprüfen:

var name = '余光';

function foo() {
  console.log(name); // 余光
}

(function (func) {
    var name = '老王';

    func()
})(foo); // 余光
Hier können wir verstehen, dass Abschlüsse nach der Erstellung von Funktionen erstellt werden. Sie speichern die Bereichskette des oberen Kontexts und speichern sie in

> bereits vage ist, können Sie sich auch ein paar Minuten Zeit nehmen, um den Artikel „Ausführungskontext in JavaScript“ zu lesen. [[scope]][[scope]]

1.4 Zusammenfassung

Hinweis: Die Aussage, dass der Abschluss eine zurückgegebene Unterfunktion innerhalb einer Funktion ist, ist an sich richtig

, aber es kommt darauf an was Ausgangspunkt: In ECMAScript bezieht sich Abschluss auf:

    Aus theoretischer Sicht: alle Funktionen. Weil sie alle beim Erstellen die Daten des oberen Kontexts speichern. Dies gilt auch für einfache globale Variablen, da der Zugriff auf globale Variablen in einer Funktion dem Zugriff auf freie Variablen entspricht. Zu diesem Zeitpunkt wird der äußerste Bereich verwendet.
  • Aus praktischer Sicht gelten folgende Funktionen als Schließungen:
  • Sie existiert auch dann noch, wenn der Kontext, in dem sie erstellt wurde, zerstört wurde (z. B. , eine innere Funktion wird in der Funktion zurückgegeben)
    • bezieht sich auf die freie Variable im Code
Zusammenfassung:

Geschlossen Der Paketcodeblock ist eine Kombination von Daten in dem Kontext, in dem der Codeblock erstellt wird.
  • Ein Abschluss ist eine Funktion, die die internen Variablen anderer Funktionen lesen kann eine Brücke zwischen den internen und externen Links der Funktion
  • Unterschiedliche Perspektiven haben unterschiedliche Interpretationen von Abschlüssen
  • Hinweis: Dies sind nicht alle Abschlüsse, genau wie wenn Sie gefragt werden – was ist ein Abschluss, Ihre obige Antwort nicht. Wenn Sie dieses Thema nicht beenden, führt dies häufig zu weiteren Themen.

Ein genauerer Blick auf Abschlüsse in JavaScript

2. Versuchen Sie, den Abschluss zu analysieren

Es ist immer noch der klassische Code:

Zuerst Wir analysieren die Änderungen im Ausführungskontextstapel und im Ausführungskontext in diesem Code.
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}

var foo = checkscope();
foo(); // local scope

    Geben Sie den globalen Code ein, erstellen Sie einen globalen Ausführungskontext und verschieben Sie den globalen Ausführungskontext in den Ausführungskontextstapel
  • Initialisierung des globalen Ausführungskontexts
  • Checkscope-Funktion ausführen, Checkscope-Funktionsausführungskontext erstellen, Checkscope-Ausführungskontext wird in den Ausführungskontextstapel verschoben
  • Checkscope-Ausführungskontextinitialisierung, Variable erstellen Objekt, Bereichskette, Dies usw.
  • Die Checkscope-Funktion wird ausgeführt und der Checkscope-Ausführungskontext wird aus dem Ausführungskontextstapel entfernt
  • 执行 f 函数,创建 f 函数执行上下文,f 执行上下文被压入执行上下文栈

  • f 执行上下文初始化,创建变量对象、作用域链、this等

  • f 函数执行完毕,f 函数上下文从执行上下文栈中弹出

Ein genauerer Blick auf Abschlüsse in JavaScript

f 函数执行的时候,checkscope 函数上下文已经被销毁了啊(即从执行上下文栈中被弹出),怎么还会读取到 checkscope 作用域下的 scope 值呢?

当我们了解了具体的执行过程后,我们知道 f 执行上下文维护了一个作用域链:

因为这个作用域链:

  • f 函数依然可以读取到 checkscopeContext.AO 的值;
  • f 函数引用了 checkscopeContext.AO 中的值的时候,即使 checkscopeContext 被销毁了,JavaScript 依然会让 checkscopeContext.AO 活在内存中;
  • f 函数依然可以通过 f 函数的作用域链找到它,正是因为 JavaScript 做到了这一点,从而实现了闭包这个概念。

多么浪漫的思想——只要你需要我,那我我本应该被销毁,你也能找到我~

Ein genauerer Blick auf Abschlüsse in JavaScript

三、经典问题

3.1 多个对象引用同一个[[Scope]],你遇到过吗?

直接上代码:

var child1;
var child2;
function parent() {
    var x = 1;

    child1 = function () {
        console.log(++x)
    };
    child2 = function () {
        console.log(--x)
    };
}
parent();
child1(); // 2
child1(); // 3
child2(); // 2

大家可能不理解,child1child他们两个函数在创建后都保存了上层上下文,万万没想到,同一个上下文创建的闭包是共用一个[[scope]]属性的,某个闭包对其中[[Scope]]的变量做修改会影响到其他闭包对其变量的读取。

3.2 闭包轻松解决的经典问题

大家一定对下面这段代码很眼熟:

var arr = []
for(var i = 0; i < 10; i++){
    arr[i] = function () {
        console.log(i)
    }
}
arr[0](); // 10
arr[1](); // 10
arr[2](); // 10
arr[3](); // 10

我们这么解释它:同一个上下文中创建的闭包是共用一个[[Scope]]属性的

因此上层上下文中的变量i是可以很容易就被改变的。

arr[0],arr[1]…arr[9]他们共用一个[[scope]],最终执行的时候结果当然一样。

如何利用闭包来解决这个问题呢?

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

我们通过立即执行匿名函数的方式隔离了作用域,当执行 arr[0] 函数的时候,arr[0] 函数的作用域链发生了改变:

arr[0]Context = {
    Scope: [AO, 匿名函数Context.AO globalContext.VO]
}

匿名函数执行上下文的AO为:

匿名函数Context = {
    AO: {
        arguments: {
            0: 0,
            length: 1
        },
        i: 0
    }
}

我们看到,这时函数的[[Scope]]属性就有了真正想要的值了,为了达到这样的目的,我们不得不在[[Scope]]中创建额外的变量对象。要注意的是,在返回的函数中,如果要获取i的值,那么该值还是会是10。

3.3 总结

  • 函数内的所有内部函数都共享一个父作用域,因此创建的闭包是共用的。
  • 利用闭包隔离作用域的特性可以解决共享作用域的问题

推荐学习:《PHP视频教程

Stellungnahme:
Dieser Artikel ist reproduziert unter:csdn.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen