Heim  >  Artikel  >  Web-Frontend  >  Sind JavaScript-Abschlüsse Gültigkeitsbereiche?

Sind JavaScript-Abschlüsse Gültigkeitsbereiche?

青灯夜游
青灯夜游Original
2021-09-07 16:58:121742Durchsuche

In JavaScript ist ein Abschluss kein Bereich, sondern ein aktives Funktionskontextobjekt, das bestehen bleiben kann. Es ist ein Objekt, das Verweise sowohl auf das Funktionsobjekt als auch auf das Bereichsobjekt enthält. Verschlüsse werden hauptsächlich verwendet, um Variablen oder Werte in der Bereichskette oder Prototypenkette abzurufen.

Sind JavaScript-Abschlüsse Gültigkeitsbereiche?

Die Betriebsumgebung dieses Tutorials: Windows 7-System, JavaScript-Version 1.8.5, Dell G3-Computer.

Wir wissen, dass die Reihenfolge der Suche nach Bezeichnern in der Bereichskette darin besteht, Ebene für Ebene beginnend mit dem aktuellen Bereich zu suchen. Daher können Variablen innerhalb einer JavaScript-Funktion über eine Bereichskette Variablen außerhalb der Funktion lesen, umgekehrt können Variablen außerhalb der Funktion jedoch im Allgemeinen keine Variablen innerhalb der Funktion lesen. In praktischen Anwendungen ist es manchmal notwendig, auf die lokalen Variablen einer Funktion außerhalb der Funktion zuzugreifen. In diesem Fall ist die Verwendung von Abschlüssen die häufigste Methode.

Der Abschluss ist eine der wichtigen Funktionen von JavaScript und spielt eine wichtige Rolle in der funktionalen Programmierung. In diesem Abschnitt werden die Struktur und die grundlegende Verwendung des Abschlusses vorgestellt.

Alsowas ist Schließung?

Ein Abschluss ist ein aktives Funktionskontextobjekt, das bestehen bleiben kann. Es ist ein Objekt, das Verweise sowohl auf Funktionsobjekte als auch auf Bereichsobjekte enthält. Verschlüsse werden hauptsächlich verwendet, um Variablen oder Werte in der Bereichskette oder Prototypenkette abzurufen. Die gebräuchlichste Methode zum Erstellen eines Abschlusses besteht darin, eine innere Funktion (auch verschachtelte Funktion genannt) innerhalb einer Funktion zu deklarieren und die innere Funktion zurückzugeben.

Zu diesem Zeitpunkt können Sie die interne Funktion erhalten, indem Sie die Funktion außerhalb der Funktion aufrufen und dann die interne Funktion aufrufen, um auf die lokalen Variablen der Funktion zuzugreifen. Die interne Funktion zu diesem Zeitpunkt ist ein Abschluss. Obwohl gemäß dem Konzept des Abschlusses alle JavaScript-Funktionen, die auf externe Variablen zugreifen, Abschlüsse sind, bezieht sich das, was wir Abschlüsse nennen, in den meisten Fällen tatsächlich auf interne Funktionsabschlüsse.

Abschlüsse können einige Daten als private Eigenschaften kapseln, um einen sicheren Zugriff auf diese Variablen zu gewährleisten. Diese Funktion bringt große Vorteile für Anwendungen. Es ist zu beachten, dass bei unsachgemäßer Verwendung von Verschlüssen auch unerwartete Probleme auftreten können. Im Folgenden werden wir anhand einiger Beispiele die Entstehung, Verwendung, mögliche Probleme und Lösungen von Verschlüssen demonstrieren.

Grundprinzip der Bildung

Wenn die Funktion aufgerufen wird, wird ein temporäres Kontextaktivitätsobjekt generiert. Es ist das Objekt der obersten Ebene des Funktionsbereichs. Alle privaten Methoden, Variablen, Parameter, privaten Funktionen usw. im Bereich sind als Attribute des kontextaktiven Objekts vorhanden. Nachdem die Funktion

aufgerufen wurde, wird das kontextaktive Objekt standardmäßig sofort freigegeben, um die Belegung von Systemressourcen zu vermeiden. Wenn jedoch auf die privaten Variablen, Parameter, privaten Funktionen usw. innerhalb der Funktion von der Außenwelt verwiesen wird, bleibt das kontextaktive Objekt vorübergehend bestehen, bis alle externen Verweise gelöscht werden.

Der Funktionsumfang ist jedoch geschlossen und für die Außenwelt nicht zugänglich. Unter welchen Umständen kann die Außenwelt also auf private Mitglieder innerhalb einer Funktion zugreifen?

Gemäß der Bereichskette kann die innere Funktion auf die privaten Mitglieder der äußeren Funktion zugreifen. Wenn die innere Funktion auf die privaten Mitglieder der äußeren Funktion verweist und die innere Funktion an die Außenwelt übergeben wird oder für die Außenwelt offen ist, wird ein Abschlusskörper gebildet. Diese externe Funktion ist ein Abschlusskörper. Nach dem Aufruf wird das aktive Objekt nicht vorübergehend gelöscht und seine Eigenschaften bleiben weiterhin bestehen. Die privaten Mitglieder der externen Funktion können kontinuierlich über die interne Funktion gelesen und geschrieben werden.

Verschlussstruktur

Ein typischer Verschlusskörper ist eine Funktion einer verschachtelten Struktur. Die innere Funktion verweist auf die privaten Mitglieder der äußeren Funktion, und gleichzeitig wird auf die innere Funktion von der Außenwelt verwiesen. Wenn die äußere Funktion aufgerufen wird, wird ein Abschluss gebildet. Diese Funktion wird auch Abschlussfunktion genannt.

Das Folgende ist eine typische Verschlussstruktur.

function f(x) {  //外部函数
    return function (y) {  //内部函数,通过返回内部函数,实现外部引用
        return x + y;  //访问外部函数的参数
    };
}
var c = f(5);  //调用外部函数,获取引用内部函数
console.log(c(6));  //调用内部函数,原外部函数的参数继续存在

Der Parsing-Prozess wird wie folgt kurz beschrieben:

  • Während der Vorkompilierungsphase des JavaScript-Skripts werden die deklarierte Funktion f und die Variable c zunächst lexikalisch vorparst.

  • Rufen Sie während der JavaScript-Ausführung die Funktion f auf und übergeben Sie den Wert 5.

  • Beim Parsen der Funktion f werden die Ausführungsumgebung (Funktionsbereich) und das aktive Objekt erstellt und die Parameter, privaten Variablen und internen Funktionen werden den Eigenschaften des aktiven Objekts zugeordnet.

  • Der Wert des Parameters x ist 5, was dem x-Attribut des aktiven Objekts zugeordnet ist.

  • Die innere Funktion referenziert den Parameter x über die Bereichskette, wurde jedoch noch nicht ausgeführt.

  • Nachdem die externe Funktion aufgerufen wurde, kehrt die interne Funktion zurück, wodurch die interne Funktion von der externen Variablen c referenziert wird.

  • Der JavaScript-Parser erkennt, dass auf die Eigenschaften des aktiven Objekts der externen Funktion von der Außenwelt verwiesen wird, und kann die Registrierung des aktiven Objekts nicht aufheben, sodass er weiterhin die Existenz des Objekts im Speicher aufrechterhält.

  • Wenn c aufgerufen wird, dh wenn die innere Funktion aufgerufen wird, können Sie sehen, dass der im Parameter x der äußeren Funktion gespeicherte Wert weiterhin vorhanden ist. Auf diese Weise können nachfolgende Operationen implementiert werden und x+y=5=6=11 wird zurückgegeben.

Die folgende Strukturform kann auch einen Abschluss bilden: Verweisen Sie über die globale Variable auf die interne Funktion, sodass die interne Funktion nach außen geöffnet werden kann.

var c;  //声明全局变量
function f(x) {  //外部函数
    c = function (y) {  //内部函数,通过向全局变量开放实现外部引用
        return x + y;  //访问外部函数的参数
    };
}
f(5);  //调用外部函数
console.log(c(6));  //使用全局变量c调用内部函数,返回11

Abschlussvarianten

Abschlüsse lassen sich neben verschachtelten Funktionen auch leicht bilden, wenn externe Referenzen auf private Arrays oder Objekte innerhalb der Funktion vorgenommen werden.

var add;  //全局变量
function f() {  //外部函数
    var a = [1,2,3];  //私有变量,引用型数组
    add = function (x) {  //测试函数,对外开放
        a[0] = x * x;  //修改私有数组的元素值
    }
    return a;  //返回私有数组的引用
}
var c = f();
console.log(c[0]);  //读取闭包内数组,返回1
add(5);  //测试修改数组
console.log(c[0]);  //读取闭包内数组,返回25
add(10);  //测试修改数组
console.log(c[0]);  //读取闭包内数组,返回100

与函数相同,对象和数组也是引用型数据。调用函数 f,返回私有数组 a 的引用,即传值给局部变量 c,而 a 是函数 f 的私有变量,当被调用后,活动对象继续存在,这样就形成了闭包。

这种特殊形式的闭包没有实际应用价值,因为其功能单一,只能作为一个静态的、单向的闭包。而闭包函数可以设计各种复杂的运算表达式,它是函数式变成的基础。

反之,如果返回的是一个简单的值,就无法形成闭包,值传递是直接复制。外部变量 c 得到的仅是一个值,而不是对函数内部变量的引用。这样当函数调用后,将直接注销对象。

function f(x) {  //外部函数
    var a = 1;  //私有变量
    return a;
}
var c = f(5);
console.log(c);  //仅是一个值,返回1

使用闭包

下面结合示例介绍闭包的简单使用,以加深对闭包的理解。

示例1

使用闭包实现优雅的打包,定义存储器。

var f = function () {  //外部函数
    var a = [];  //私有数组初始化
    return function (x) {  //返回内部函数
        a.push(x);  //添加元素
        return a;  //返回私有数组
    };
} ()  //直接调用函数,生成执行环境
var a = f(1);  //添加值
console.log(a);  //返回1
var b = f(2);  //添加值
console.log(b);  //返回1,2

在上面示例中,通过外部函数设计一个闭包,定义一个永久的存储器。当调用外部函数生成执行环境之后,就可以利用返回的匿名函数不断地的向闭包体内的数组 a 传入新值,传入的值会持续存在。

示例2

在网页中事件处理函数很容易形成闭包。

<script>
function f() {
    var a = 1;
    b = function () {
        console.log("a =" + a);
    }
    c = function () {
        a ++;
    }
    d = function () {
        a --;
    }
}
</script>
<button onclick="f()">生成闭包</button>
<button onclick="b()">查看 a 的值</button>
<button onclick="c()">递增</button>
<button onclick="d()">递减</button>

在浏览器中浏览时,首先点击“生成闭包”按钮,生成一个闭包;点击“查看 a 的值”按钮,可以随时查看闭包内私有变量 a 的值;点击“递增”“递减”按钮时,可以动态修改闭包内变量 a 的值,效果如图所示。

Sind JavaScript-Abschlüsse Gültigkeitsbereiche?

闭包的局限性

闭包的价值是方便在表达式运算过程中存储数据。但是,它的缺点也不容忽视。

  • 由于函数调用后,无法注销调用对象,会占用系统资源,在脚本中大量使用闭包,容易导致内存泄漏。解决方法:慎用闭包,不要滥用。

  • 由于闭包的作用,其保存的值是动态,如果处理不当容易出现异常或错误。

示例

设计一个简单的选项卡效果。HTML 结构如下:

<div class="tab_wrap">
    <ul class="tab" id="tab">
        <li id="tab_1" class="hover">Tab1</li>
        <li id="tab_2" class="normal">Tab2</li>
        <li id="tab_3" class="normal">Tab3</li>
    </ul>
    <div class="content" id="content">
        <div id="content_1" class="show"><img  scr="image/1.jpg"    style="max-width:90%" / alt="Sind JavaScript-Abschlüsse Gültigkeitsbereiche?" ></div>
        <div id="content_2" class="show"><img  scr="image/2.jpg"    style="max-width:90%" / alt="Sind JavaScript-Abschlüsse Gültigkeitsbereiche?" ></div>
        <div id="content_3" class="show"><img  scr="image/3.jpg"    style="max-width:90%" / alt="Sind JavaScript-Abschlüsse Gültigkeitsbereiche?" ></div>
    </div>
</div>

下面请看 JavaScript 脚本。

window.onload = function () {
    var tab = document.getElementById("tab").getElementsByTagName("li"),
        content = document.getElementById("content").getElementByTagName("div");
    for (var i = 0; i < tab.length;i ++) {
        tab[i].addEventListener("mouseover"), function () {
            for (var n = 0; n < tab.length; n ++) {
                tab[n].className = "normal";
                content[n].className = "none";
            }
            tab[i].className = "hover";
            content[i].className = "show";
        });
    }
}

在 load 事件处理函数中,使用 for 语句为每个 li 属性元素绑定 mouseover 事件;在 mouseover 事件处理函数中重置所有选项卡 li 的类样式,然后设置当前 li 选项卡高亮显示,同时显示对应的内容容器。

但是在浏览器中预览时,会发现浏览器抛出异常。

SCRIPT5007:无法设置未定义或 null 引用的属性"className"

在 mouseover 事件处理函数中跟踪变量 i 的值,i 的值都变为了 3,tab[3] 自然是一个 null,所以也不能够读取 className 属性。

【原因分析】

上面 JavaScript 代码是一个典型的嵌套函数结构。外部函数为 load 事件处理函数,内部函数为 mouseover 事件处理函数,变量 i 为外部函数的私有变量。

通过事件绑定,mouseover 事件处理函数被外界引用(li 元素),这样就形成了一个闭包体。虽然在 for 语句中为每个选项卡 li 分别绑定事件处理函数,但是这个操作是动态的,因此 tab[i] 中 i 的值也是动态的,所以就出现了上述异常。

【解决方法】

解决闭包的缺陷,最简单的方法是阻断内部函数对外部函数的变量引用,这样就形成了闭包体。针对本示例,我们可以在内部函数(mouseover 事件处理函数)外边增加一层防火墙,不让其直接引用外部变量。

window.load = function () {
    var tab = document.getElementById("tab").getElementsByTagName("li"),
        content = document.getElementById("content").getElementsByTagName("div");
    for (var i = 0; i < tab.length; i ++ ) {
        (function (j) {
            tab[j].addEventListener("number", function () {
                for (var n = 0; n < tab.length; n ++) {
                    tab[n].className = "normal";
                    content[n].className = "none";
                }
                tab[j].className = "hover";
                conteng[j].className = "show";
            });
        }) (i);
    }
}

在 for 语句中,直接调用匿名函数,把外部函数的 i 变量传给调用函数,在调用函数中接收这个值,而不是引用外部变量 i,规避了闭包体带来的困惑。

【推荐学习:javascript高级教程

Das obige ist der detaillierte Inhalt vonSind JavaScript-Abschlüsse Gültigkeitsbereiche?. 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