Heim  >  Artikel  >  Web-Frontend  >  JavaScript durchbricht das Scope-Gefängnis

JavaScript durchbricht das Scope-Gefängnis

黄舟
黄舟Original
2017-02-27 14:25:11931Durchsuche

JavaScript durchbricht das Scope-Gefängnis


Als lose Sprache verfügt JavaScript über viele atemberaubende Funktionen (oft einige schwer fassbare und seltsame Funktionen), in diesem Artikel werden wir wird vorstellen, wie man einige Funktionen von JavaScript nutzt, um das „Bereichsgefängnis“ herkömmlicher Programmiersprachen zu durchbrechen.

1. JavaScript-Deklarationsförderung

Viele Menschen sollten wissen, dass js die Merkmale einer Variablendeklarationsförderung und einer Funktionsdeklarationsförderung aufweist. Unabhängig davon, ob Sie es bereits verstanden haben, prüfen Sie, ob das Ergebnis der Ausführung des folgenden Codes Ihren Erwartungen entspricht:

var a=123;
//可以运行
abc();
//报错:def is not a function
def();
function abc(){
    //undefined
    console.log(a);
    var a="hello";
    //hello
    console.log(a);
}
var def=function(){
    console.log("def");
}

Tatsächlich scannt js den Code beim Ausführen in zwei Runden. In der ersten Runde werden Variablen initialisiert; in der zweiten Runde wird der Code ausgeführt. Der Ausführungscode der zweiten Runde ist leicht zu verstehen, der Prozess der ersten Runde ist jedoch unklarer. Im Einzelnen werden in der ersten Runde die folgenden drei Dinge ausgeführt:

(1) Funktionsparameter deklarieren und initialisieren

(2) Lokale Variablen deklarieren, einschließlich der Zuweisung anonymer Funktionen zu einer lokalen Variablen, aber tun nicht initialisieren

(3) Funktionen deklarieren und initialisieren

Nachdem wir diese theoretischen Grundlagen verstanden haben, wurde der obige Code nach der ersten Scanrunde tatsächlich vom js-Compiler „übersetzt“ und wird wie folgt Code:

var a;
a=123;
function abc(){
    //局部变量,将会取代外部的a
    var a;
    //undefined
    console.log(a);
    var a="hello";
    //hello
    console.log(a);
}
var def;
//可以运行
abc();
//报错:def is not a function
def();
var def=function(){
    console.log("def");
}

Schauen wir uns nun die in den Kommentaren gezeigte Laufzeitausgabe des Programms an. Halten Sie das für sinnvoll? Dies ist die Rolle, die die Förderung der js-Deklaration dabei spielt.

Nachdem wir den Mechanismus der js-Deklarationsförderung kennengelernt haben, schauen wir uns den folgenden Code an:

var obj={};
function start(){
    //undefined
    //This is obj.a
    console.log(obj.a);
    //undefined
    //This is a
    console.log(a);
    //成功输出
    //成功输出
    console.log("页面执行完成");
}

start();
var a="This is a";
obj.a="This is obj.a";
start();

Die erste Zeile des obigen Kommentars gibt die erste Ausführung von start() an method Die zweite Zeile stellt die Ausgabe der zweiten Ausführung der start()-Methode dar. Es ist ersichtlich, dass aufgrund der vorhandenen js-Deklarationsförderung kein Fehler gemeldet wurde, wenn die start()-Methode zweimal ausgeführt wurde. Schauen wir uns eine kleine Modifikation dieses Beispiels an:

var obj={};
function start(){
    //undefined
    //This is obj.a
    console.log(obj.a);
    //报错
    //This is a
    console.log(a);
    //因为上一行的报错导致后续代码不执行
    //成功输出
    console.log("页面执行完成");
}

start();
/*---------------另一个js文件----------------*/
var a="This is a";
obj.a="This is obj.a";
start();

Zu diesem Zeitpunkt meldet der Code console.log(a) aufgrund der Verschiebung der Deklaration der a-Variablen in eine andere js-Datei einen Fehler, sodass Nachfolgender js-Code wird nicht mehr ausgeführt. Allerdings wird die Methode start() auch beim zweiten Mal normal ausgeführt. Aus diesem Grund wird fast überall empfohlen, den „js-Namespace“ zu verwenden, um verschiedene js-Dateien bereitzustellen. Nachfolgend verwenden wir einen Code, um zusammenzufassen, wie Deklarationsförderung + Namespace den Aktionskäfig auf clevere Weise durchbrechen kann:

/*-----------------第一个js文件----------------*/
var App={};
App.first=(function(){
    function a(){
        App.second.b();
    }

    return {
        a:a
    };
})();

/*-----------------另一个js文件----------------*/
App.second=(function(){
    function b(){
        console.log("This is second.b");
    }

    return {
        b:b
    };
})();

//程序起点,输出This is second.b
App.first.a();

Dieses Programm meldet keine Fehler. Wir können es zur ersten js-Datei hinzufügen Der Zugriff auf nachfolgende Eigenschaften im App-Namespace ist kein Problem, solange der Programmstartpunkt nach allen erforderlichen Zuweisungen ausgeführt wird. Dieses Beispiel zeigt erfolgreich, wie die dynamischen Eigenschaften der js-Sprache durch eine sinnvolle Gestaltung der Codestruktur voll ausgenutzt werden können.

Nachdem die Leser dies gelesen haben, denken sie vielleicht, dass dieser Artikel eine Art Schlagzeile ist. Die obige Technik ist nur eine „Illusion“, die durch das Code-Layout erzeugt wurde: Es scheint, dass der vorherige Code auf nicht vorhandene Eigenschaften zugreift. aber tatsächlich ist die Reihenfolge der tatsächlichen Ausführung angemessen und korrekt. Anschließend wird in diesem Artikel die eigentliche Technik des „aktionsübergreifenden Zugriffs“ vorgestellt.

2.js-Ausführungscode

Jeder weiß, dass die js-Sprache eine „eval()“-Methode hat, eine typische Methode, die „den Käfigeffekt wirklich bricht“. Schauen Sie sich den folgenden Code an:

(function(){
    var code="console.log(a)";
    //This is a bird
    test(code);

    function test(code){
        console.log=function(arg){
            console.info("This is a "+arg);
        };
        var a="bird";
        eval(code);
    }
})();

Nachdem ich diesen Code gelesen habe, glaube ich, dass viele Menschen über das Wunder von js seufzen müssen: „Das kann auch funktionieren?!“. Ja. Die test()-Methode kann aufgrund des Deklarationsförderungsmechanismus im Voraus aufgerufen und normal ausgeführt werden. Die test()-Methode akzeptiert einen Codeparameter. Innerhalb der test()-Methode haben wir die console.log-Methode neu geschrieben, das Ausgabeformat geändert und eine private Variable var a="bird" innerhalb des Tests definiert. Am Ende der Testmethode verwenden wir eval, um den Code dynamisch auszuführen. Das Druckergebnis ist sehr magisch: Der Browser verwendet die von uns neu geschriebene Methode console.log, um die private Variable a innerhalb der Testmethode auszudrucken. Dies ist eine vollständige Bereichsisolierung.

Es gibt viele ähnliche Methoden in js, wie zum Beispiel: eval(), setTimeout(), setInterval() und einige Konstruktionsmethoden nativer Objekte. Es sind jedoch zwei Punkte zu beachten:

(1) Diese Methode verringert die Ausführungseffizienz des Programms erheblich. Jeder weiß, dass js selbst eine interpretierte Sprache ist und ihre Leistung bereits um viele Stufen langsamer ist als die kompilierter Sprachen. Wenn wir auf dieser Grundlage Methoden wie eval verwenden, um einen Zeichenfolgencode „neu zu kompilieren“, ist die Leistung des Programms viel langsamer.

(2) Durch das Programmieren auf diese Weise wird die Komplexität des Codes erheblich erhöht, und Sie werden den von Ihnen geschriebenen Code nicht in wenigen Minuten verstehen können. In diesem Artikel wird diese Methode vorgestellt, in der Hoffnung, dass die Leser ein umfassendes Verständnis der grammatikalischen Eigenschaften von js erhalten, damit sie Fehler besser korrigieren und beheben können. In diesem Artikel wird die Verwendung des zweiten Ansatzes im Code auf Produktionsebene überhaupt nicht empfohlen.

Das Obige ist der Inhalt von JavaScript, der den Käfig des Geltungsbereichs durchbricht. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn)!


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