Heim >Web-Frontend >js-Tutorial >JavaScript Advanced Series – Umfang und Namespace
Implizite globale Variablen
Lokale Variablen
Variablendeklaration-Heben (Hoisting)
Namensauflösungsreihenfolge
Namespace
Fazit
Obwohl JavaScript unterstützt wird Codeausschnitte, die durch ein Paar geschweifte Klammern erstellt werden, unterstützen nicht den Bereich auf Blockebene, sondern nur den Funktionsbereich.
function test() { // 一个作用域 for(var i = 0; i < 10; i++) { // 不是一个作用域 // count } console.log(i); // 10 }
Anmerkung des Übersetzers: Wenn sich die linke Klammer des Rückgabeobjekts und der Rückgabe nicht in derselben Zeile befinden, tritt ein Fehler auf.
(Hinweis: Wenn es sich nicht in einer Zuweisungsanweisung, sondern in einem Rückgabeausdruck oder Funktionsparameter befindet, wird {...} als Codesegment analysiert, nicht als wörtliche Syntaxanalyse von Das Objekt. Wenn das automatische Einfügen von Semikolons berücksichtigt wird, kann dies zu einigen subtilen Fehlern führen.
// 译者注:下面输出 undefined function add(a, b) { return a + b; } console.log(add(1, 2));
Es gibt keine explizite Namespace-Definition in JavaScript, was bedeutet, dass alle Objekte unter definiert sind ein weltweit gemeinsam genutzter Namensraum.
Jedes Mal, wenn auf eine Variable verwiesen wird, durchläuft JavaScript den gesamten Bereich nach oben, bis es die Variable findet. Wenn der globale Gültigkeitsbereich erreicht ist, die Variable aber immer noch nicht gefunden wird, wird eine ReferenceError-Ausnahme ausgelöst.
Implizite globale Variablen
// 脚本 A foo = '42'; // 脚本 B var foo = '42'
Die beiden oben genannten Skripte haben unterschiedliche Auswirkungen. Skript A definiert die Variable foo im globalen Bereich, während Skript B die Variable foo im aktuellen Bereich definiert.
Auch hier ist der obige Effekt völlig anders: Die Deklaration von Variablen ohne Verwendung von var führt zur Erstellung impliziter globaler Variablen.
// 全局作用域 var foo = 42; function test() { // 局部作用域 foo = 21; } test(); foo; // 21
Das Deklarieren der foo-Variablen ohne Verwendung des Schlüsselworts var innerhalb des Funktionstests überschreibt die externe Variable mit demselben Namen. Das scheint auf den ersten Blick kein großes Problem zu sein, aber wenn Sie Tausende von Codezeilen haben, kann die Deklaration von Variablen ohne Verwendung von var zu Fehlern führen, die schwer aufzuspüren sind.
// 全局作用域 var items = [/* 数组 */]; for(var i = 0; i < 10; i++) { subLoop(); } function subLoop() { // subLoop 函数作用域 for(i = 0; i < 10; i++) { // 没有使用 var 声明变量 // 干活 } }
Die äußere Schleife wird nach dem ersten Aufruf von subLoop beendet, da subLoop die globale Variable i überschreibt. Dieser Fehler kann vermieden werden, indem die Variable in der zweiten for-Schleife mit var deklariert wird. Lassen Sie das Schlüsselwort var niemals weg, wenn Sie eine Variable deklarieren, es sei denn, dies ist das gewünschte Verhalten, das sich auf den äußeren Bereich auswirkt.
Lokale Variablen
Lokale Variablen in JavaScript können nur auf zwei Arten deklariert werden: eine als Funktionsparameter und die andere über das Schlüsselwort var.
// 全局变量 var foo = 1; var bar = 2; var i = 2; function test(i) { // 函数 test 内的局部作用域 i = 5; var foo = 3; bar = 4; } test(10);
foo und i sind lokale Variablen innerhalb des Funktionstests, und die Zuweisung an bar überschreibt die gleichnamige Variable im globalen Bereich.
Variablendeklaration hochziehen (Hoisting)
JavaScript hebt Variablendeklarationen hoch. Dies bedeutet, dass sowohl var-Ausdrücke als auch Funktionsdeklarationen an die Spitze des aktuellen Bereichs gehoben werden.
bar(); var bar = function() {}; var someValue = 42; test(); function test(data) { if (false) { goo = 1; } else { var goo = 2; } for(var i = 0; i < 100; i++) { var e = data[i]; } }
Der obige Code wird vor der Ausführung konvertiert. JavaScript hebt Variablenausdrücke und Funktionsdeklarationen an die Spitze des aktuellen Bereichs.
// var 表达式被移动到这里 var bar, someValue; // 缺省值是 'undefined' // 函数声明也会提升 function test(data) { var goo, i, e; // 没有块级作用域,这些变量被移动到函数顶部 if (false) { goo = 1; } else { goo = 2; } for(i = 0; i < 100; i++) { e = data[i]; } } bar(); // 出错:TypeError,因为 bar 依然是 'undefined' someValue = 42; // 赋值语句不会被提升规则(hoisting)影响 bar = function() {}; test();
Das Fehlen eines Blockbereichs führt nicht nur dazu, dass var-Ausdrücke von innerhalb der Schleife nach außen verschoben werden, sondern macht auch einige if-Ausdrücke schwerer lesbar.
Im Originalcode scheint der if-Ausdruck die globale Variable goo zu ändern, tatsächlich ändert er jedoch die lokale Variable, nachdem die Heraufstufungsregel angewendet wurde.
Ohne Kenntnisse über das Heben scheint der folgende Code eine ReferenceError-Ausnahme auszulösen.
// 检查 SomeImportantThing 是否已经被初始化 if (!SomeImportantThing) { var SomeImportantThing = {}; }
Eigentlich funktioniert der obige Code einwandfrei, da der var-Ausdruck an die Spitze des globalen Bereichs gehoben wird.
var SomeImportantThing; // 其它一些代码,可能会初始化 SomeImportantThing,也可能不会 // 检查是否已经被初始化 if (!SomeImportantThing) { SomeImportantThing = {}; }
Anmerkung des Übersetzers: Auf der Nettuts+-Website gibt es einen Artikel, der das Heben vorstellt, und der darin enthaltene Code ist sehr aufschlussreich.
// 译者注:来自 Nettuts+ 的一段代码,生动的阐述了 JavaScript 中变量声明提升规则 var myvar = 'my value'; (function() { alert(myvar); // undefined var myvar = 'local value'; })();
Reihenfolge der Namensauflösung
Alle Bereiche in JavaScript, einschließlich des globalen Bereichs, haben einen speziellen Namen, der auf das aktuelle Objekt verweist. Es gibt auch eine Standardvariable arguments im Funktionsumfang, die die an die Funktion übergebenen Parameter enthält. Beim Zugriff auf die Variable foo innerhalb einer Funktion sucht JavaScript beispielsweise in der folgenden Reihenfolge:
Ob es im aktuellen Bereich eine Definition von var foo gibt.
Ob die formalen Parameter der Funktion den Foo-Namen verwenden.
Ob die Funktion selbst foo heißt.
Kehren Sie zum vorherigen Umfang zurück und beginnen Sie erneut bei Nr. 1.
Namespace
Ein häufiger Fehler, der dadurch verursacht wird, dass es nur einen globalen Bereich gibt, sind Namenskonflikte. In JavaScript lässt sich dies leicht mit anonymen Wrappern lösen.
(Hinweis: Benutzerdefinierte Argumentparameter verhindern die Erstellung nativer Argumentobjekte.)
(function() { // 函数创建一个命名空间 window.foo = function() { // 对外公开的函数,创建了闭包 }; })(); // 立即执行此匿名函数
Anonyme Funktionen gelten als Ausdrücke und müssen daher aus Gründen der Aufrufbarkeit zuerst ausgeführt werden.
( // 小括号内的函数首先被执行 function() {} ) // 并且返回函数对象 () // 调用上面的执行结果,也就是函数对象
Es gibt einige andere Möglichkeiten, Funktionsausdrücke aufzurufen. Die folgenden beiden Methoden haben beispielsweise eine unterschiedliche Syntax, aber die Wirkung ist genau die gleiche.
// 另外两种方式 +function(){}(); (function(){}());
Fazit
Es wird empfohlen, anonyme Wrapper (Anmerkung des Übersetzers: selbstausführende anonyme Funktionen) zu verwenden, um Namespaces zu erstellen. Dies verhindert nicht nur Namenskonflikte, sondern erleichtert auch die Modularisierung des Programms.
Außerdem gilt die Verwendung globaler Variablen als schlechte Praxis. Ein solcher Code ist fehleranfällig und kostspielig in der Wartung.
Das Obige ist der Inhalt der erweiterten JavaScript-Serie – Umfang und Namespace. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn).