übergeben - javascript variablen benennen




Was ist der Umfang der Variablen in JavaScript? (17)

Alte Schule JavaScript

Traditionell hat JavaScript nur zwei Arten von Geltungsbereich:

  1. Globaler Geltungsbereich : Variablen sind in der gesamten Anwendung vom Start der Anwendung bekannt (*)
  2. Funktionsumfang : Variablen sind innerhalb der Funktion, in der sie deklariert sind, vom Start der Funktion bekannt (*)

Ich werde darauf nicht eingehen, da es bereits viele andere Antworten gibt, die den Unterschied erklären.

Modernes JavaScript

Die neuesten JavaScript-Spezifikationen erlauben nun auch einen dritten Bereich:

  1. Blockbereich : Variablen sind innerhalb des Blocks bekannt, in dem sie deklariert sind, ab dem Zeitpunkt ihrer Deklaration (**)

Wie erstelle ich Blockbereichsvariablen?

Traditionell erstellen Sie Ihre Variablen wie folgt:

var myVariable = "Some text";

Block-Scope-Variablen werden wie folgt erstellt:

let myVariable = "Some text";

Worin besteht also der Unterschied zwischen Funktionsumfang und Blockumfang?

Beachten Sie den folgenden Code, um den Unterschied zwischen Funktionsumfang und Blockbereich zu verstehen:

// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here

function loop(arr) {
    // i IS known here, but undefined
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( var i = 0; i < arr.length; i++ ) {
        // i IS known here, and has a value
        // j IS NOT known here
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( let j = 0; j < arr.length; j++ ) {
        // i IS known here, and has a value
        // j IS known here, and has a value
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here
}

loop([1,2,3,4]);

for( var k = 0; k < arr.length; k++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS NOT known here
};

for( let l = 0; l < arr.length; l++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS known here, and has a value
};

loop([1,2,3,4]);

// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here

Hier können wir sehen, dass unsere Variable j nur in der ersten for-Schleife bekannt ist, aber nicht davor und danach. Dennoch ist unsere Variable i in der gesamten Funktion bekannt.

Beachten Sie außerdem, dass Blockbereichsvariablen nicht bekannt sind, bevor sie deklariert werden, da sie nicht gehisst sind. Es ist Ihnen auch nicht erlaubt, dieselbe Block-Bereichsvariable innerhalb desselben Blocks neu zu deklarieren. Dies macht Block-Scoped-Variablen weniger fehleranfällig als Global- oder Funktions-Scoped-Variablen, die gehisst werden und die bei mehreren Deklarationen keine Fehler erzeugen.

Ist es heute sicher, Block-Scope-Variablen zu verwenden?

Ob es heute sicher ist oder nicht, hängt von Ihrer Umgebung ab:

  • Wenn Sie serverseitigen JavaScript-Code ( Node.js ) schreiben, können Sie die let Anweisung sicher verwenden.

  • Wenn Sie clientseitigen JavaScript-Code schreiben und einen transpiler (wie Traceur ) verwenden, können Sie die let Anweisung sicher verwenden, jedoch ist Ihr Code in Bezug auf die Leistung wahrscheinlich alles andere als optimal.

  • Wenn Sie clientseitigen JavaScript-Code schreiben und keinen transpiler verwenden, müssen Sie die Browserunterstützung in Betracht ziehen.

    Heute, 23. Februar 2016, sind dies einige Browser, die entweder nicht unterstützt werden oder nur teilweise Unterstützung haben:

    • Internet Explorer 10 und niedriger (keine Unterstützung)
    • Firefox 43 und darunter (keine Unterstützung)
    • Safari 9 und darunter (keine Unterstützung)
    • Opera Mini 8 und darunter (keine Unterstützung)
    • Android-Browser 4 und niedriger (keine Unterstützung)
    • Opera 36 und darunter (teilweise Unterstützung)
    • Chome 51 und darunter (teilweise Unterstützung)

So behalten Sie den Überblick über die Browserunterstützung

Eine aktuelle Übersicht, welche Browser die let Anweisung zum Zeitpunkt des Lesens dieser Antwort unterstützen, finden Can I Use Seite Can I Use .

(*) Globale und funktional beschränkte Variablen können initialisiert und verwendet werden, bevor sie deklariert werden, weil JavaScript-Variablen hoisted . Dies bedeutet, dass Deklarationen immer ganz oben stehen.

(**) Block-Bereichsvariablen werden nicht gehisst

Was ist der Umfang der Variablen in Javascript? Haben sie den gleichen Bereich innerhalb wie außerhalb einer Funktion? Oder ist es überhaupt wichtig? Wo werden die Variablen gespeichert, wenn sie global definiert sind?


Moderne Js, ES6 +, ' const ' und ' let '

Sie sollten Block-Scoping für jede von Ihnen erstellte Variable verwenden, genau wie in den meisten anderen Hauptsprachen. var ist veraltet . Dies macht Ihren Code sicherer und wartungsfreundlicher.

const sollte für 95% der Fälle verwendet werden . Es macht es so, dass sich die Variablenreferenz nicht ändern kann. Array-, Objekt- und DOM-Knoteneigenschaften können sich ändern und sollten wahrscheinlich const .

let sollte für jede Variable verwendet werden, die eine Neuzuweisung erwartet. Dies beinhaltet innerhalb einer for-Schleife. Wenn Sie den Wert über die Initialisierung hinaus ändern, verwenden Sie let .

Block scope bedeutet, dass die Variable nur innerhalb der Klammern verfügbar ist, in denen sie deklariert ist. Dies gilt auch für interne Bereiche, einschließlich anonymer Funktionen, die in Ihrem Bereich erstellt wurden.


1) Es gibt einen globalen Bereich, einen Funktionsumfang und die Bereiche mit und mit Fang. Es gibt im Allgemeinen keinen 'Block'-Ebenenbereich für Variablen - die With- und die Catch-Anweisungen fügen ihren Blöcken Namen hinzu.

2) Bereiche sind von Funktionen bis zum globalen Bereich verschachtelt.

3) Eigenschaften werden aufgelöst, indem man die Prototypkette durchgeht. Die with-Anweisung bringt Objekteigenschaftsnamen in den lexikalischen Bereich, der durch den with-Block definiert wird.

BEARBEITEN: ECMAAScript 6 (Harmony) ist auf Unterstützung eingestellt, und ich weiß, dass Chrome eine "Harmony" -Flagge erlaubt, also vielleicht unterstützt es es.

Lassen Sie das Block-Level-Scoping unterstützen, aber Sie müssen das Schlüsselwort verwenden, um dies zu ermöglichen.

EDIT: Basierend auf Benjamins Hinweis auf die With & Catch-Anweisungen in den Kommentaren habe ich den Beitrag bearbeitet und mehr hinzugefügt. Sowohl die With- als auch die Catch-Anweisung führen Variablen in ihre jeweiligen Blöcke ein, und das ist ein Blockumfang. Diese Variablen sind als Alias ​​für die Eigenschaften der Objekte definiert, die an sie übergeben werden.

 //chrome (v8)

 var a = { 'test1':'test1val' }
 test1   // error not defined
 with (a) { var test1 = 'replaced' }
 test1   // undefined
 a       // a.test1 = 'replaced'

EDIT: Erklärungsbeispiel:

test1 ist auf den with-Block beschränkt, wird jedoch mit a.test1 abgeglichen. 'Var test1' erstellt eine neue Variable test1 im oberen lexikalischen Kontext (Funktion oder global), es sei denn, es ist eine Eigenschaft von a - was es ist.

Huch! Seien Sie vorsichtig mit 'mit' - genau wie var ein Noop ist, wenn die Variable bereits in der Funktion definiert ist, ist es auch ein Noop in Bezug auf die aus dem Objekt importierten Namen! Ein wenig Heads-Up über den bereits definierten Namen würde dies viel sicherer machen. Ich persönlich werde nie damit arbeiten.



Es gibt fast nur zwei Arten von JavaScript-Bereichen:

  • Der Gültigkeitsbereich jeder var-Deklaration ist mit der am unmittelbaresten umschließenden Funktion verknüpft
  • Wenn es keine umschließende Funktion für eine var-Deklaration gibt, handelt es sich um einen globalen Gültigkeitsbereich

Daher erstellen alle Blöcke außer Funktionen keinen neuen Bereich. Das erklärt, warum For-Schleifen äußere Bereichsvariablen überschreiben:

var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5

Funktionen stattdessen verwenden:

var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10

Im ersten Beispiel gab es keinen Blockbereich, daher wurden die ursprünglich deklarierten Variablen überschrieben. Im zweiten Beispiel gab es einen neuen Bereich aufgrund der Funktion, so dass die anfänglich deklarierten Variablen SHADOWED waren und nicht überschrieben wurden.

Das ist alles, was Sie in Bezug auf JavaScript-Scoping wissen müssen, außer:

Sie können also sehen, dass JavaScript-Scoping eigentlich extrem einfach ist, wenn auch nicht immer intuitiv. Ein paar Dinge zu beachten:

  • var-Deklarationen werden an den Anfang des Bereichs gehisst. Das heißt, egal wo die var-Deklaration auftritt, für den Compiler ist es so, als ob die var selbst oben passiert
  • Mehrere var-Deklarationen innerhalb desselben Bereichs werden kombiniert

Also dieser Code:

var i = 1;
function abc() {
  i = 2;
  var i = 3;
}
console.log(i);     // outputs 1

ist äquivalent zu:

var i = 1;
function abc() {
  var i;     // var declaration moved to the top of the scope
  i = 2;
  i = 3;     // the assignment stays where it is
}
console.log(i);

Dies mag gegensätzlich erscheinen, macht aber aus der Perspektive eines imperativen Sprachentwicklers Sinn.


Es gibt nur Funktionsbereiche in JS. Nicht Bereiche blockieren! Sie können sehen, was auch hissen ist.

var global_variable = "global_variable";
var hoisting_variable = "global_hoist";

// Global variables printed
console.log("global_scope: - global_variable: " + global_variable);
console.log("global_scope: - hoisting_variable: " + hoisting_variable);

if (true) {
    // The variable block will be global, on true condition.
    var block = "block";
}
console.log("global_scope: - block: " + block);

function local_function() {
    var local_variable = "local_variable";
    console.log("local_scope: - local_variable: " + local_variable);
    console.log("local_scope: - global_variable: " + global_variable);
    console.log("local_scope: - block: " + block);
    // The hoisting_variable is undefined at the moment.
    console.log("local_scope: - hoisting_variable: " + hoisting_variable);

    var hoisting_variable = "local_hoist";
    // The hoisting_variable is now set as a local one.
    console.log("local_scope: - hoisting_variable: " + hoisting_variable);
}

local_function();

// No variable in a separate function is visible into the global scope.
console.log("global_scope: - local_variable: " + local_variable);

Hier ist ein Beispiel:

<script>

var globalVariable = 7; //==window.globalVariable

function aGlobal( param ) { //==window.aGlobal(); 
                            //param is only accessible in this function
  var scopedToFunction = {
    //can't be accessed outside of this function

    nested : 3 //accessible by: scopedToFunction.nested
  };

  anotherGlobal = {
    //global because there's no `var`
  }; 

}

</script>

Sie möchten Schließungen untersuchen und herausfinden, wie Sie diese verwenden, um private Mitglieder zu werden .


Ich denke, das Beste, was ich tun kann, ist eine Reihe von Beispielen zu studieren. JavaScript-Programmierer werden praktisch nach ihrem Umfang eingestuft. Es kann manchmal ziemlich kontraintuitiv sein.

  1. Eine global gültige Variable

    // global scope
    var a = 1;
    
    function one() {
      alert(a); // alerts '1'
    }
    
  2. Lokaler Umfang

    // global scope
    var a = 1;
    
    function two(a) {
      // local scope
      alert(a); // alerts the given argument, not the global value of '1'
    }
    
    // local scope again
    function three() {
      var a = 3;
      alert(a); // alerts '3'
    }
    
  3. Intermediate : Kein Blockbereich in JavaScript (ES5; ES6 führt ein)

    ein.

    var a = 1;
    
    function four() {
      if (true) {
        var a = 4;
      }
    
      alert(a); // alerts '4', not the global value of '1'
    }
    

    b.

    var a = 1;
    
    function one() {
      if (true) {
        let a = 4;
      }
    
      alert(a); // alerts '1' because the 'let' keyword uses block scoping
    }
    
  4. Zwischenstufe : Objekteigenschaften

    var a = 1;
    
    function Five() {
      this.a = 5;
    }
    
    alert(new Five().a); // alerts '5'
    
  5. Fortgeschritten : Schließung

    var a = 1;
    
    var six = (function() {
      var a = 6;
    
      return function() {
        // JavaScript "closure" means I have access to 'a' in here,
        // because it is defined in the function in which I was defined.
        alert(a); // alerts '6'
      };
    })();
    
  6. Fortgeschritten : Prototyp-basierte Scope-Auflösung

    var a = 1;
    
    function seven() {
      this.a = 7;
    }
    
    // [object].prototype.property loses to
    // [object].property in the lookup chain. For example...
    
    // Won't get reached, because 'a' is set in the constructor above.
    seven.prototype.a = -1;
    
    // Will get reached, even though 'b' is NOT set in the constructor.
    seven.prototype.b = 8;
    
    alert(new seven().a); // alerts '7'
    alert(new seven().b); // alerts '8'
    
  7. Global + Local : Ein extra komplexer Fall

    var x = 5;
    
    (function () {
        console.log(x);
        var x = 10;
        console.log(x); 
    })();
    

    Dies wird undefined und 10 statt 5 und 10 ausgeben, da JavaScript Variablendeklarationen (nicht Initialisierungen) immer an den Anfang des Bereichs verschiebt, was den Code äquivalent zu:

    var x = 5;
    
    (function () {
        var x;
        console.log(x);
        x = 10;
        console.log(x); 
    })();
    
  8. Catch-Klausel-Variable

    var e = 5;
    console.log(e);
    try {
        throw 6;
    } catch (e) {
        console.log(e);
    }
    console.log(e);
    

    Dies wird 5 , 6 , 5 ausdrucken. Innerhalb der Fangklausel werden globale und lokale Variablen angezeigt. Aber dieser spezielle Bereich gilt nur für die gefangene Variable. Wenn Sie var f; schreiben var f; Innerhalb der catch-Klausel ist es genau so, als ob Sie es vor oder nach dem try-catch-Block definiert hätten.


In "Javascript 1.7" (Mozilla-Erweiterung zu Javascript) kann man auch Block-Scope-Variablen mit let Anweisung deklarieren:

 var a = 4;
 let (a = 3) {
   alert(a); // 3
 }
 alert(a);   // 4

JavaScript hat nur zwei Arten von Scope:

  1. Global Scope : Global ist nichts anderes als ein Fensterlevel. Hier ist die Variable in der gesamten Anwendung vorhanden.
  2. Funktionsumfang : Die in einer Funktion mit dem Schlüsselwort var deklarierte Variable hat einen Funktionsumfang.

Wenn eine Funktion aufgerufen wird, wird ein Objekt für den Variablenbereich erstellt (und in die Bereichskette eingeschlossen), dem Variablen in JavaScript folgen.

        a = "global";
         function outer(){ 
              b = "local";
              console.log(a+b); //"globallocal"
         }
outer();

Scope-Kette ->

  1. Fensterebene - a und outer Funktion befinden sich auf der obersten Ebene in der Umfangskette.
  2. Wenn die äußere Funktion ein neues variable scope object aufgerufen hat (und in der Bereichskette enthalten ist), wird die Variable b darin eingefügt.

Wenn nun eine Variable a benötigt wird, sucht sie zuerst nach dem nächsten Variablenbereich und wenn die Variable nicht da ist, wird sie zum nächsten Objekt der Variablenbereichskette verschoben. Dies ist in diesem Fall die Fensterebene.


Jedem Teil des JavaScript-Codes (globaler Code oder Funktionen) ist eine Bereichskette zugeordnet. Diese Gültigkeitsbereichskette ist eine Liste oder Kette von Objekten, die die Variablen definiert, die für diesen Code "im Geltungsbereich" sind. Wenn JavaScript den Wert einer Variablen x (ein Prozess namens variable resolution ) nachschlagen muss, wird zunächst das erste Objekt in der Kette betrachtet. Wenn dieses Objekt eine Eigenschaft mit dem Namen x , wird der Wert dieser Eigenschaft verwendet. Wenn das erste Objekt keine Eigenschaft namens x , setzt JavaScript die Suche mit dem nächsten Objekt in der Kette fort. Wenn das zweite Objekt keine Eigenschaft mit dem Namen x , wird die Suche zum nächsten Objekt weitergeleitet und so weiter. Wenn x keine Eigenschaft eines Objekts in der Gültigkeitsbereichskette ist, ist x für diesen Code nicht im Geltungsbereich und ein ReferenceError tritt auf. Im JavaScript-Code auf oberster Ebene (dh Code, der nicht in Funktionsdefinitionen enthalten ist) besteht die Scope-Kette aus einem einzelnen Objekt, dem globalen Objekt. In einer nicht verschachtelten Funktion besteht die Geltungsbereichskette aus zwei Objekten. Das erste ist das Objekt, das die Parameter und lokalen Variablen der Funktion definiert, und das zweite ist das globale Objekt. In einer geschachtelten Funktion enthält die Bereichskette drei oder mehr Objekte. Es ist wichtig zu verstehen, wie diese Kette von Objekten erzeugt wird. Wenn eine Funktion DEFINIERT ist , speichert sie die aktuelle Gültigkeitsbereichskette. Wenn diese Funktion INVOKED ist , erstellt sie ein neues Objekt zum Speichern ihrer lokalen Variablen und fügt dieses neue Objekt der gespeicherten Bereichskette hinzu, um eine neue, längere Kette zu erstellen, die den Bereich für diesen Funktionsaufruf darstellt. Dies wird für verschachtelte Funktionen interessanter, da jedes Mal, wenn die äußere Funktion aufgerufen wird, die innere Funktion erneut definiert wird. Da die Gültigkeitsbereichskette bei jedem Aufruf der äußeren Funktion unterschiedlich ist, unterscheidet sich die innere Funktion bei jeder Definition geringfügig: Der Code der inneren Funktion ist bei jedem Aufruf der äußeren Funktion identisch, aber die zugehörige Umfangskette code will be different . This notion of a scope chain is crucial for understanding closures .


Um nur zu den anderen Antworten hinzuzufügen, ist scope eine Nachschlageliste aller deklarierten Bezeichner (Variablen) und erzwingt einen strikten Satz von Regeln, wie diese dem aktuell ausgeführten Code zugänglich sind. Diese Suche kann für die Zwecke der Zuordnung zu der Variablen, die eine LHS-Referenz (linke Seite) ist, oder für den Zweck des Abrufens ihres Wertes, der eine RHS-Referenz (rechte Seite) ist, dienen. Diese Nachschlagefunktionen werden von der JavaScript-Engine beim Kompilieren und Ausführen des Codes intern ausgeführt.

Aus dieser Perspektive denke ich, dass ein Bild helfen würde, das ich im Scopes and Closures eBook von Kyle Simpson gefunden habe:

Zitat aus seinem E-Book:

Das Gebäude repräsentiert das verschachtelte Scope-Regelwerk unseres Programms. Die erste Etage des Gebäudes repräsentiert Ihren aktuell ausgeführten Bereich, egal wo Sie sind. Die oberste Ebene des Gebäudes ist der globale Geltungsbereich. Sie lösen LHS- und RHS-Referenzen auf, indem Sie auf Ihre aktuelle Etage schauen, und wenn Sie sie nicht finden, nehmen Sie den Aufzug in die nächste Etage, schauen dort hin, dann zur nächsten und so weiter. Sobald Sie das oberste Stockwerk (den globalen Bereich) erreicht haben, finden Sie entweder, was Sie suchen, oder Sie nicht. Aber du musst trotzdem aufhören.

Bemerkenswert ist, dass "Scope Look-Up stoppt, sobald das erste Match gefunden wurde".

Diese Idee von "scope levels" erklärt, warum "this" mit einem neu erstellten scope geändert werden kann, wenn es in einer verschachtelten Funktion nachgeschlagen wird. Hier ist ein Link, der in all diese Details eingeht, alles , was Sie über Javascript Scope wissen wollten


ECMAScript 6 introduced the let and const keywords. These keywords can be used in place of the var keyword. Contrary to the var keyword, the let and const keywords support the declaration of local scope inside block statements.

var x = 10
let y = 10
const z = 10
{
  x = 20
  let y = 20
  const z = 20
  {
    x = 30
    // x is in the global scope because of the 'var' keyword
    let y = 30
    // y is in the local scope because of the 'let' keyword
    const z = 30
    // z is in the local scope because of the 'const' keyword
    console.log(x) // 30
    console.log(y) // 30
    console.log(z) // 30
  }
  console.log(x) // 30
  console.log(y) // 20
  console.log(z) // 20
}

console.log(x) // 30
console.log(y) // 10
console.log(z) // 10

Global: variable declared outside of a function

Local: variable declared inside a function, and can only be called in that scope


In JavaScript there are two types of scope:

  • Local scope
  • Global scope

The Below function has a local scope variable carName . And this variable is not accessible from outside of the function.

function myFunction() {
    var carName = "Volvo";
    alert(carName);
    // code here can use carName
}

The Below Class has a Global scope variable carName . And this variable is accessible from everywhere in the class.

class {

    var carName = " Volvo";

    // code here can use carName

    function myFunction() {
        alert(carName);
        // code here can use carName 
    }
}

My understanding is that there are 3 scopes: global scope, available globally; local scope, available to an entire function regardless of blocks; and block scope, only available to the block, statement, or expression on which it was used. Global and local scope are indicated with the keyword 'var', either within a function or outside, and block scope is indicated with the keyword 'let'.

For those that believe there is only global and local scope, please explain why Mozilla would have an entire page describing the nuances of block scope in JS.

let


Try this curious example. In the example below if a were a numeric initialized at 0, you'd see 0 and then 1. Except a is an object and javascript will pass f1 a pointer of a rather than a copy of it. The result is that you get the same alert both times.

var a = new Date();
function f1(b)
{
    b.setDate(b.getDate()+1);
    alert(b.getDate());
}
f1(a);
alert(a.getDate());






scope