Was ist eine kurze Einführung in das lexikalische Scoping?
Was ist lexikalischer Umfang?
Subba Rao
Khaled Alshaya
Ich verstehe sie anhand von Beispielen. 🙂
Zuerst, lexikalischer Umfang (auch genannt statischer Geltungsbereich), in C-ähnlicher Syntax:
void fun()
{
int x = 5;
void fun2()
{
printf("%d", x);
}
}
Jede innere Ebene kann auf ihre äußeren Ebenen zugreifen.
Es gibt einen anderen Weg, genannt dynamischer Umfang verwendet von der ersten Implementierung von Lispelnwieder in einer C-ähnlichen Syntax:
void fun()
{
printf("%d", x);
}
void dummy1()
{
int x = 5;
fun();
}
void dummy2()
{
int x = 10;
fun();
}
Hier fun
kann entweder zugreifen x
in dummy1
oder dummy2
oder irgendein x
in jeder Funktion, die aufruft fun
mit x
darin erklärt.
dummy1();
wird 5 drucken,
dummy2();
druckt 10.
Der erste heißt statisch, weil er zur Kompilierzeit abgeleitet werden kann, und der zweite heißt dynamisch, weil der äußere Gültigkeitsbereich dynamisch ist und vom Kettenaufruf der Funktionen abhängt.
Ich finde das statische Scoping einfacher für das Auge. Die meisten Sprachen gingen irgendwann so, sogar Lisp (kann beides, oder?). Dynamisches Scoping ist wie das Übergeben von Referenzen aller Variablen an die aufgerufene Funktion.
Als Beispiel dafür, warum der Compiler den äußeren dynamischen Bereich einer Funktion nicht ableiten kann, betrachten Sie unser letztes Beispiel. Wenn wir so etwas schreiben:
if(/* some condition */)
dummy1();
else
dummy2();
Die Aufrufkette hängt von einer Laufzeitbedingung ab. Wenn es wahr ist, sieht die Aufrufkette so aus:
dummy1 --> fun()
Wenn die Bedingung falsch ist:
dummy2 --> fun()
Der äußere Geltungsbereich von fun
in beiden Fällen ist der Anrufer plus der Anrufer des Anrufers und so weiter.
Nur um zu erwähnen, dass die C-Sprache weder verschachtelte Funktionen noch dynamisches Scoping zulässt.
-
Ich möchte auch auf ein sehr sehr leicht verständliches Tutorial hinweisen, das ich gerade gefunden habe. Araks Beispiel ist nett, aber möglicherweise zu kurz für jemanden, der mehr Beispiele benötigt (eigentlich im Vergleich zu anderen Sprachen …). Schau mal. Es ist wichtig zu verstehen Dasda dieses Schlüsselwort uns dazu bringt, den lexikalischen Umfang zu verstehen. howtonode.org/what-is-this
– CppLearner
8. August 2011 um 6:13 Uhr
-
Dies ist eine gute Antwort. Aber die Frage ist mit markiert
JavaScript
. Daher denke ich, dass dies nicht als akzeptierte Antwort markiert werden sollte. Der lexikalische Umfang speziell in JS ist anders– Boyang
1. Oktober 2016 um 10:29 Uhr
-
Extrem gute Antwort. Danke. @Boyang Ich bin anderer Meinung. Ich bin kein Lisp-Programmierer, fand das Lisp-Beispiel jedoch hilfreich, da es ein Beispiel für dynamisches Scoping ist, das Sie in JS nicht erhalten.
– Dudewad
10. Oktober 2016 um 20:36 Uhr
-
Anfangs dachte ich, das Beispiel sei gültiger C-Code und war verwirrt, ob es in C dynamisches Scoping gibt. Vielleicht könnte der Haftungsausschluss am Ende vor das Codebeispiel verschoben werden?
– Yangshun Tay
8. April 2017 um 7:28 Uhr
-
Dies ist immer noch eine sehr hilfreiche Antwort, aber ich denke, @Boyang ist richtig. Diese Antwort bezieht sich auf „Ebene“, was eher dem Blockbereich entspricht, den C hat. JavaScript hat standardmäßig keinen Geltungsbereich auf Blockebene, also innerhalb von a
for
Schleife ist das typische Problem. Der lexikalische Umfang für JavaScript liegt nur auf Funktionsebene, es sei denn, ES6let
oderconst
wird genutzt.– icc97
19. April 2018 um 11:44 Uhr
Pierre Spring
Versuchen wir die kürzest mögliche Definition:
Lexikalischer Umfang definiert, wie Variablennamen in verschachtelten Funktionen aufgelöst werden: innere Funktionen enthalten den Gültigkeitsbereich von übergeordneten Funktionen, selbst wenn die übergeordnete Funktion zurückgegeben wurde.
Das ist alles, was dazu gehört!
-
Der letzte Teil: „auch wenn die Elternfunktion zurückgekehrt ist“ heißt Closure.
– Juanma Menendez
13. März 2019 um 15:18 Uhr
-
Lexical Scoping & Closure in nur einem Satz verstanden. Danke!!
– Kerker
1. Mai 2020 um 14:36 Uhr
kta
var scope = "I am global";
function whatismyscope(){
var scope = "I am just a local";
function func() {return scope;}
return func;
}
whatismyscope()()
Der obige Code gibt “Ich bin nur ein Einheimischer” zurück. Es wird nicht “Ich bin ein Global” zurückkommen. Weil die Funktion func() dort zählt, wo sie ursprünglich definiert wurde, was im Bereich der Funktion whatismyscope liegt.
Es wird nicht stören, was auch immer es aufgerufen wird (der globale Bereich / sogar aus einer anderen Funktion), deshalb wird der globale Bereichswert I am global nicht gedruckt.
Dies wird lexikalisches Scoping genannt, wobei “Funktionen werden unter Verwendung der Bereichskette ausgeführt, die bei ihrer Definition gültig war” – gemäß JavaScript Definition Guide.
Der lexikalische Umfang ist ein sehr, sehr mächtiges Konzept.
Hoffe das hilft..:)
-
Es ist eine sehr schöne Erklärung. Ich möchte noch etwas hinzufügen, wenn Sie die Funktion func() {return this.scope;} schreiben, dann wird “I am global” zurückgegeben. Verwenden Sie einfach dieses Schlüsselwort, und Ihr Bereich wird geändert
– Rajesh Kumar Bhawsar
11. September 2019 um 3:01 Uhr
Lexikalischer (auch bekannt als statischer) Geltungsbereich bezieht sich auf die Bestimmung des Geltungsbereichs einer Variablen ausschließlich auf der Grundlage ihrer Position innerhalb des textuellen Codekorpus. Eine Variable bezieht sich immer auf ihre Umgebung der obersten Ebene. Es ist gut, es zu verstehen Beziehung zum dynamischen Bereich.
Ralph M. Rickenbach
Scope definiert den Bereich, in dem Funktionen, Variablen und dergleichen verfügbar sind. Die Verfügbarkeit einer Variablen wird beispielsweise innerhalb ihres Kontexts definiert, sagen wir der Funktion, Datei oder dem Objekt, in dem sie definiert sind. Wir nennen diese normalerweise lokale Variablen.
Der lexikalische Teil bedeutet, dass Sie den Geltungsbereich aus dem Lesen des Quellcodes ableiten können.
Der lexikalische Geltungsbereich wird auch als statischer Geltungsbereich bezeichnet.
Der dynamische Geltungsbereich definiert globale Variablen, die nach ihrer Definition von überall aus aufgerufen oder referenziert werden können. Manchmal werden sie als globale Variablen bezeichnet, obwohl globale Variablen in den meisten Programmiersprachen lexikalischen Gültigkeitsbereich haben. Das heißt, es kann aus dem Lesen des Codes abgeleitet werden, dass die Variable in diesem Kontext verfügbar ist. Vielleicht muss man einer uses- oder include-Klausel folgen, um die Anweisung oder Definition zu finden, aber der Code/Compiler kennt die Variable an dieser Stelle.
Im Gegensatz dazu suchen Sie beim dynamischen Scoping zuerst in der lokalen Funktion, dann suchen Sie in der Funktion, die die lokale Funktion aufgerufen hat, dann suchen Sie in der Funktion, die diese Funktion aufgerufen hat, und so weiter, den Aufrufstapel hinauf. “Dynamisch” bezieht sich auf Änderungen, da der Aufrufstapel bei jedem Aufruf einer bestimmten Funktion unterschiedlich sein kann und die Funktion daher möglicherweise auf unterschiedliche Variablen trifft, je nachdem, von wo aus sie aufgerufen wird. (sehen Hier)
Ein interessantes Beispiel für dynamischen Bereich finden Sie unter Hier.
Einige Beispiele in Delphi/Object Pascal
Delphi hat einen lexikalischen Gültigkeitsbereich.
unit Main;
uses aUnit; // makes available all variables in interface section of aUnit
interface
var aGlobal: string; // global in the scope of all units that use Main;
type
TmyClass = class
strict private aPrivateVar: Integer; // only known by objects of this class type
// lexical: within class definition,
// reserved word private
public aPublicVar: double; // known to everyboday that has access to a
// object of this class type
end;
implementation
var aLocalGlobal: string; // known to all functions following
// the definition in this unit
end.
Am nächsten kommt Delphi dem dynamischen Bereich durch das Funktionspaar RegisterClass()/GetClass(). Zur Verwendung siehe hier.
Nehmen wir an, dass die Zeit RegisterClass([TmyClass]) aufgerufen wird, um eine bestimmte Klasse zu registrieren, kann nicht durch Lesen des Codes vorhergesagt werden (es wird in einer vom Benutzer aufgerufenen Schaltflächenklickmethode aufgerufen), Code, der GetClass(‘TmyClass’) aufruft, wird ein Ergebnis erhalten oder nicht. Der Aufruf von RegisterClass() muss sich nicht im lexikalischen Bereich der Unit befinden, die GetClass() verwendet;
Eine weitere Möglichkeit für dynamischen Umfang sind Anonyme Methoden (Closures) in Delphi 2009, da sie die Variablen ihrer aufrufenden Funktion kennen. Es folgt dem Aufrufpfad von dort nicht rekursiv und ist daher nicht vollständig dynamisch.
-
Tatsächlich ist private in der gesamten Einheit zugänglich, in der die Klasse definiert ist. Aus diesem Grund wurde in D2006 „Strict private“ eingeführt.
– Marco van de Voort
26. Juni 2009 um 22:34 Uhr
-
+1 für einfache Sprache (im Gegensatz zu komplizierter Sprache und Beispielen ohne viel Beschreibung)
– Knallt
27. April 2010 um 17:48 Uhr
Peter Mortensen
Ich liebe die voll funktionsfähigen, sprachunabhängigen Antworten von Leuten wie @Arak. Da diese Frage markiert wurde JavaScript Ich möchte jedoch einige Anmerkungen hinzufügen, die für diese Sprache sehr spezifisch sind.
In JavaScript sind unsere Auswahlmöglichkeiten für den Bereich:
- so wie es ist (keine Bereichsanpassung)
- lexikalisch
var _this = this; function callback(){ console.log(_this); }
- gebunden
callback.bind(this)
Ich denke, es ist erwähnenswert, dass JavaScript hat nicht wirklich dynamische Scoping. .bind
passt die an this
Schlüsselwort, und das ist nah, aber technisch nicht dasselbe.
Hier ist ein Beispiel, das beide Ansätze demonstriert. Sie tun dies jedes Mal, wenn Sie eine Entscheidung darüber treffen, wie Callbacks zu bereichern sind, damit dies für Promises, Event-Handler und mehr gilt.
Lexikalisch
Hier ist, was Sie nennen könnten Lexical Scoping
von Callbacks in JavaScript:
var downloadManager = {
initialize: function() {
var _this = this; // Set up `_this` for lexical access
$('.downloadLink').on('click', function () {
_this.startDownload();
});
},
startDownload: function(){
this.thinking = true;
// Request the file from the server and bind more callbacks for when it returns success or failure
}
//...
};
Gebunden
Eine andere Art des Umfangs ist die Verwendung Function.prototype.bind
:
var downloadManager = {
initialize: function() {
$('.downloadLink').on('click', function () {
this.startDownload();
}.bind(this)); // Create a function object bound to `this`
}
//...
Diese Methoden sind, soweit ich weiß, verhaltensmäßig gleichwertig.
-
Tatsächlich ist private in der gesamten Einheit zugänglich, in der die Klasse definiert ist. Aus diesem Grund wurde in D2006 „Strict private“ eingeführt.
– Marco van de Voort
26. Juni 2009 um 22:34 Uhr
-
+1 für einfache Sprache (im Gegensatz zu komplizierter Sprache und Beispielen ohne viel Beschreibung)
– Knallt
27. April 2010 um 17:48 Uhr
Lexikalischer Geltungsbereich bedeutet, dass in einer verschachtelten Gruppe von Funktionen, Die inneren Funktionen haben Zugriff auf die Variablen und andere Ressourcen ihres übergeordneten Geltungsbereichs.
Das bedeutet, dass die Funktionen des Kindes lexikalisch an den Ausführungskontext ihrer Eltern gebunden sind.
Der lexikalische Geltungsbereich wird manchmal auch als bezeichnet statischer Geltungsbereich.
function grandfather() {
var name="Hammad";
// 'likes' is not accessible here
function parent() {
// 'name' is accessible here
// 'likes' is not accessible here
function child() {
// Innermost level of the scope chain
// 'name' is also accessible here
var likes="Coding";
}
}
}
Was Sie am lexikalischen Geltungsbereich bemerken werden, ist, dass er vorwärts arbeitet, was bedeutet, dass auf den Namen durch die Ausführungskontexte seiner untergeordneten Elemente zugegriffen werden kann.
Aber es funktioniert nicht rückwärts zu seinen Eltern, was bedeutet, dass die Variable likes
kann von seinen Eltern nicht aufgerufen werden.
Dies sagt uns auch, dass Variablen mit demselben Namen in verschiedenen Ausführungskontexten von oben nach unten im Ausführungsstapel Vorrang erhalten.
Eine Variable mit einem ähnlichen Namen wie eine andere Variable in der innersten Funktion (oberster Kontext des Ausführungsstapels) hat eine höhere Priorität.
In Podcast 58 fördert Joel Fragen wie diese, da er möchte, dass SO DER Ort für Antworten wird, auch wenn sie an anderen Stellen beantwortet wurden. Das ist eine berechtigte Frage, auch wenn man sie etwas höflicher formulieren könnte.
– Ralph M. Rickenbach
26. Juni 2009 um 5:30 Uhr
@rahul Ich verstehe, dass es eine alte Frage ist. Aber ich bin mir sicher, dass SO sogar im Jahr 2009 von den Fragestellern erwartet wurde etwas grundlegender Aufwand hin zur Lösung. So wie es aussieht, wird es nicht angezeigt irgendein Anstrengung überhaupt. Vielleicht wurde es deshalb von vielen abgelehnt?
– PP
12. September 2013 um 12:05 Uhr
Es ist möglich, dass der Fragesteller beim Verfassen dieser Frage nicht fließend Englisch spricht (oder war).
– Martin
16. Januar 2014 um 19:24 Uhr
Die Frage ist höflich, er sagt einfach, was er will. Es steht Ihnen frei zu antworten. Übertriebene Höflichkeit ist hier nicht nötig.
– Markus Siebeneicher
24. April 2014 um 11:08 Uhr
Ich denke, Fragen wie diese sind großartig, weil sie Inhalte für SO erstellen. IMO, wen kümmert es, wenn die Frage keine Mühe macht … die Antworten werden großartigen Inhalt haben, und das ist es, was in diesem Message Board zählt.
– Jwan622
4. Oktober 2014 um 22:42 Uhr