Ich werde das auch nicht wissen, gehen nach Hause und farm.
Die Codekopie lautet wie folgt:
Löschen Sie das iisObject [Schlüssel]
oder
Löschen Sie thisIsObject.Key
Lassen Sie uns übrigens über die Verwendung des Löschens sprechen
Vor ein paar Wochen hatte ich die Gelegenheit, Stoyan Stefanovs objektorientiertes JavaScript-Buch zu lesen. Dieses Buch ist bei Amazon (12 Rezensionen, 5 Sterne) stark bewertet. Ich war gespannt, ob es sich um ein so empfohlenes Buch handelte. Deshalb habe ich angefangen, das Kapitel der Funktionen zu lesen. Ich schätze die Art und Weise, wie dieses Buch Dinge erklärt, und die Beispiele sind sehr schön und schrittweise organisiert, und es scheint, dass selbst Anfänger dieses Wissen leicht beherrschen können. Fast sofort entdeckte ich im gesamten Kapitel ein interessantes Missverständnis - das Löschen von Funktionsfunktionen. Es gibt auch einige andere Fehler (z. B. den Unterschied zwischen Funktionserklärungen und Funktionsausdrücken), aber wir werden sie zu diesem Zeitpunkt nicht diskutieren.
Das Buch behauptet:
"Die Funktion wird wie eine normale Variable behandelt - sie kann in verschiedene Variablen kopiert oder sogar gelöscht". Ein Beispiel ist dieser Erklärung beigefügt:
Die Codekopie lautet wie folgt:
var sum = Funktion (a, b) {return a + b;}
var add = sum;
Summe löschen
WAHR
typeof sum;
"undefiniert"
Ignorieren Sie einige fehlende Semikolons. Können Sie sehen, wo sich die Fehler in diesen Codes befinden? Offensichtlich ist der Fehler, dass das Löschen der Summenvariablen nicht erfolgreich ist. Der Ausdruck des Löschens sollte nicht wahr zurückkehren, und die Typof -Summe sollte nicht "undefiniert" zurückgeben. All dies liegt daran, dass es unmöglich ist, Variablen in JavaScript zu löschen. Zumindest ist es in dieser Erklärung unmöglich.
Also, was genau ist in diesem Beispiel passiert? Ist es ein Fehler? Oder eine besondere Verwendung? Wahrscheinlich nicht. Dieser Code ist tatsächlich die eigentliche Ausgabe in der Firebug -Konsole, und Stoyan muss ihn als Werkzeug für schnelle Tests verwendet haben. Es ist fast so, als ob Firebug einigen anderen Löschregeln folgt. Es ist Firebug, der Stoyan veranlasst hat, in die Irre zu gehen! Also, was genau ist hier passiert?
Bevor wir diese Frage beantworten, müssen wir zunächst verstehen, wie der Löschbetreiber in JavaScript funktioniert: Was genau kann gelöscht werden und was kann nicht gelöscht werden? Heute werde ich versuchen, dies ausführlich zu erklären. Wir werden uns das "seltsame" Verhalten von Firebug ansehen und erkennen, dass es nicht so seltsam ist. Wir werden tiefer in das eintauchen, was hinter den Kulissen versteckt ist, in denen Variablen, Funktionen, Werte den Attributen zuweisen und sie löschen. Wir werden uns die Browserkompatibilität und einige der berüchtigtsten Fehler ansehen. Wir werden auch das strenge Muster von ES5 diskutieren und wie es das Verhalten von Löschen von Operatoren verändert.
Ich werde JavaScript und ECMascript tauschen, die beide ECMascript bedeuten (es sei denn, es ist offensichtlich, dass die JavaScript -Implementierung von Mozilla)
Wie erwartet sind im Internet Erklärungen des Löschens ziemlich knapp. Der MDC -Artikel ist wahrscheinlich die beste Ressource zu verstehen, aber leider fehlen einige interessante Details des Themas. Seltsamerweise ist eines der vergessenen Dinge der Grund für die seltsame Manifestation von Firebug. Und die MSDN -Referenz ist in diesen Aspekten fast nutzlos.
Theorie
Warum können wir also die Eigenschaften eines Objekts löschen:
Die Codekopie lautet wie folgt:
var o = {x: 1};
Ochsen löschen; // WAHR
Ochse; // undefiniert
Das so deklarierte Objekt kann jedoch nicht gelöscht werden:
Die Codekopie lautet wie folgt:
var x = 1;
x löschen; // FALSCH
X; // 1
Oder die Funktion:
Die Codekopie lautet wie folgt:
Funktion x () {}
x löschen; // FALSCH
typeof x; // "Funktion"
Hinweis: Wenn eine Eigenschaft nicht gelöscht werden kann, gibt der Löschbetreiber nur false zurück.
Um dies zu verstehen, müssen wir zunächst diese Konzepte zu variablen Instanzen und Attributeigenschaften beherrschen - diese Konzepte werden leider in JavaScript -Büchern selten erwähnt. Ich werde versuchen, diese Konzepte in den nächsten Absätzen kurz zu überprüfen. Diese Konzepte sind schwer zu verstehen! Wenn es Ihnen egal ist, "warum diese Dinge so funktionieren", überspringen Sie einfach dieses Kapitel.
Art des Code:
In ECMascript gibt es 3 verschiedene Arten von ausführbarem Code: Globaler Code, Funktionscode und Evalcode. Diese Typen sind in Bezug auf den Namen mehr oder weniger selbsterklärend. Hier finden Sie einen kurzen Überblick:
Wenn ein Stück Quellcode als Programm angesehen wird, wird er in einer globalen Umgebung ausgeführt und gilt als globaler Code. In einer Browserumgebung werden der Inhalt von Skriptelementen normalerweise als Programme interpretiert und daher als globaler Code ausgeführt.
Jeder Code, der direkt in einer Funktion ausgeführt wird, wird offensichtlich als Funktionscode angesehen. In einem Browser wird der Inhalt der Ereigniseigenschaften (z. B. <p onclick = "...">) normalerweise als Funktionscode interpretiert.
Schließlich wird der auf die integrierte Funktion angewendete Codetext als Bewertungscode interpretiert. Bald werden wir herausfinden, warum dieser Typ etwas Besonderes ist.
Ausführungskontext:
Wenn der ECMascript -Code ausgeführt wird, tritt er normalerweise in einem bestimmten Ausführungskontext auf. Der Ausführungskontext ist ein etwas abstraktes Entitätskonzept, mit dem Sie verstehen können, wie der Umfang und die variablen Instanzen funktionieren. Für jede der drei ausführbaren Codes gibt es einen Ausführungskontext, der ihm entspricht. Wenn eine Funktion ausgeführt wird, sagen wir, dass "Programmsteuerung in den Ausführungskontext des Funktionscode eingeht". Wenn ein Stück globaler Code ausgeführt wird, tritt die Programmsteuerung in den Ausführungskontext des globalen Codes usw. ein.
Wie Sie sehen können, kann der Ausführungskontext logisch einen Stapel bilden. Zuerst kann es ein Stück globaler Code und einen eigenen Ausführungskontext geben, und dann kann dieses Stück Code eine Funktion mit seinem (Funktions-) Ausführungskontext aufrufen. Diese Funktion kann eine andere Funktion usw. aufrufen usw. Auch wenn die Funktion rekursiv aufgerufen wird, wird sie jedes Mal in einen neuen Ausführungskontext eingegeben, wenn sie aufgerufen wird.
Aktives Objekt (Aktivierungsobjekt) / Variable -Objekt:
Jeder Ausführungskontext ist ein sogenanntes variables Objekt zugeordnet. Ähnlich wie im Ausführungskontext ist ein variables Objekt eine abstrakte Entität, ein Mechanismus zur Beschreibung variabler Instanzen. Interessanterweise werden im Quellcode deklarierte Variablen und Funktionen in der Regel diesem variablen Objekt als Eigenschaften hinzugefügt.
Wenn die Programmsteuerung in den Ausführungskontext des globalen Code eingeht, wird ein globales Objekt als variables Objekt verwendet. Genau aus diesem Grund werden Funktionsvariablen für globale Werte zu globalen Objekteigenschaften deklariert.
Die Codekopie lautet wie folgt:
/ * Denken Sie daran, dass `dies` auf globales Objekt in globalem Umfang bezieht *///
var Global_object = this;
var foo = 1;
Global_object.foo; // 1
foo === Global_object.foo; // WAHR
Funktions bar () {}
typeof global_object.bar; // "Funktion"
Global_object.bar === bar; // WAHR
Ok, globale Variablen werden also zu Eigenschaften globaler Objekte, aber was passiert mit lokalen Variablen (die im Funktionscode definierten)? Tatsächlich verhalten sie sich sehr ähnlich: Sie werden zu Eigenschaften variabler Objekte (variable Objekte). Der einzige Unterschied besteht darin, dass ein variabler Objekt bei Funktionscode kein globales Objekt, sondern ein sogenanntes Aktivierungsobjekt ist. Das aktive Objekt wird jedes Mal erstellt, wenn es in den Ausführungskontext des Funktionscode eingeht.
Nicht nur Variablen und Funktionen, die im Funktionscode deklariert sind, werden zu Eigenschaften des aktiven Objekts. Dies erfolgt auch bei jedem Funktionsparameter (der Name, der dem entsprechenden formalen Parameter entspricht) und einem speziellen Argumenteobjekt (dem Namen der Argumente). Beachten Sie, dass das aktive Objekt ein interner Beschreibungsmechanismus ist und nicht im Programmcode zugegriffen werden kann.
Die Codekopie lautet wie folgt:
(Funktion (foo) {
var bar = 2;
Funktion BAZ () {}
/*
Abstrakt
Special "Argumente" -Objekt wird zu einer Eigenschaft, die das Aktivierungsobjekt der Funktion enthält:
ACTICTION_OBJECT.Argumente; // Argumente Objekt
... sowie Argument `foo`:
ACTICTATION_OBJECT.FOO; // 1
... sowie variable `bar`:
ACTICTION_OBJECT.BAR; // 2
... sowie Funktion lokal deklariert:
typeof active_object.baz; // "Funktion"
*/
}) (1);
Schließlich werden Variablen, die im Bewertungscode deklariert sind, zu Eigenschaften variabler Objekte im Caller -Kontext. Evaling -Code verwendet lediglich variable Objekte im Ausführungskontext des Code, der ihn aufruft.
Die Codekopie lautet wie folgt:
var Global_object = this;
/* `foo` wird als Eigenschaft des Aufrufs von Kontextvariablenobjekten erstellt.
was in diesem Fall ein globales Objekt */ ist
eval ('var foo = 1;');
Global_object.foo; // 1
(Funktion(){
/* `bar` wird als Eigenschaft des aufgerufenen Kontextvariablenobjekts erstellt.
Was in diesem Fall ein Aktivierungsobjekt ist, das Funktion enthält */
eval ('var bar = 1;');
/*
Abstrakt
ACTICTION_OBJECT.BAR; // 1
*/
}) ();
Eigenschaftsattribute
Wir sind fast hier. Nachdem wir uns nun bewusst sind, was mit Variablen passiert (sie werden zu Eigenschaften), ist das einzig verbleibende Konzept, das verstanden werden muss, Eigenschaftenattribute. Jedes Attribut kann 0 oder mehr Eigenschaften haben, die aus den folgenden Sätzen ausgewählt werden: Readonly, Dontenum, Dontdelete und Intern. Sie können sie als Flaggen vorstellen - eine Funktion, die in den Eigenschaften existieren kann oder nicht. Für unsere heutige Diskussion interessieren wir uns nur für Dontdelete.
Wenn deklarierte Variablen und Funktionen zu Attributen von variablen Objekten (oder aktiven Objekten des Funktionscodes oder globalen Objekte des globalen Codes) werden, werden diese Attribute mit dem Attribut "Dontdelete" erstellt. Alle explizite (oder impliziten) Attribute werden jedoch nicht in das Attribut dontdelete einbezogen. Aus diesem Grund können wir einige Attribute löschen, aber andere nicht löschen.
Die Codekopie lautet wie folgt:
var Global_object = this;
/* `foo` ist eine Eigenschaft eines globalen Objekts.
Es wird über eine variable Deklaration erstellt und hat auch das Dontdelete -Attribut.
Deshalb kann es nicht gelöscht werden. */
var foo = 1;
Foo löschen; // FALSCH
typeof foo; // "Nummer"
/* `bar` ist eine Eigenschaft eines globalen Objekts.
Es wird durch Funktionserklärung erstellt und hat auch das Dontdelete -Attribut.
Deshalb kann es auch nicht gelöscht werden. */
Funktions bar () {}
Bar löschen; // FALSCH
typeof bar; // "Funktion"
/* `baz` ist auch eine Eigenschaft eines globalen Objekts.
Es wird jedoch über Eigenschaftenzuweisungen erstellt und hat daher kein Attribut für dontdelete.
Deshalb kann es gelöscht werden. */
Global_object.baz = 'bla';
löschen global_object.baz; // WAHR
typeof global_object.baz; // "undefiniert"
Integrierte Objekte und Dontdelete
Hier geht es also darum (dontdelete): eine besondere Eigenschaft der Eigenschaft, die steuert, ob diese Eigenschaft gelöscht werden kann. Beachten Sie, dass einige integrierte Objekte so angegeben sind, dass sie Dontdelete enthalten, sodass sie nicht gelöscht werden können. Zum Beispiel hat eine spezielle Argumentvariable (oder wie wir jetzt wissen, dass die Eigenschaft eines aktiven Objekts) dontdelete. Die Länge Eigenschaft einer Funktionsinstanz hat auch eine Dontdelete -Eigenschaft.
Die Codekopie lautet wie folgt:
(Funktion(){
/ * kann nicht löschen `argumente`, da es dontdelete */hat
Argumente löschen; // FALSCH
Typen von Argumenten; // "Objekt"
/* Die "Länge" der Funktion kann nicht löschen; es hat auch dontdelete */
Funktion f () {}
F.Length löschen; // FALSCH
typeof f.length; // "Nummer"
}) ();
Das Attribut, das dem Funktionsparameter entspricht, hat auch die Dontdelete -Funktion seit seiner Einrichtung, sodass wir es nicht löschen können.
Die Codekopie lautet wie folgt:
(Funktion (foo, bar) {
Foo löschen; // FALSCH
foo; // 1
Bar löschen; // FALSCH
Bar; // 'bla'
}) (1, 'bla');
Nicht deklarierte Aufgabe:
Sie können sich auch daran erinnern, dass eine nicht deklarierte Zuordnung eine Eigenschaft für das globale Objekt erstellt, es sei denn, die Eigenschaft wurde an anderer Stelle in dieser Bereichskette vor dem globalen Objekt gefunden. Und jetzt kennen wir den Unterschied zwischen Eigenschaftszuordnung und variabler Deklaration - letztere legt die Dontdelete -Eigenschaft fest, erstere jedoch nicht. Wir müssen klar sein, warum eine nicht deklarierte Aufgabe eine löschliche Eigenschaft erzeugt.
Die Codekopie lautet wie folgt:
var Global_object = this;
/* Erstellen Sie die globale Eigenschaft per variabler Deklaration; Eigenschaft hat dontdelete */
var foo = 1;
/* Erstellen Sie die globale Eigenschaft über nicht deklarierter Zuordnung; Eigenschaft hat kein Nichtdelete */
Bar = 2;
Foo löschen; // FALSCH
typeof foo; // "Nummer"
Bar löschen; // WAHR
typeof bar; // "undefiniert"
Bitte beachten Sie: Eigenschaften werden festgelegt, wenn das Attribut erstellt wird, und nachfolgende Zuordnungen ändern die Eigenschaften vorhandener Attribute nicht. Es ist sehr wichtig, diesen Unterschied zu verstehen.
Die Codekopie lautet wie folgt:
/ * `foo` wird als Eigenschaft mit dontdelete */erstellt
Funktion foo () {}
/* Spätere Zuweisungen ändern keine Attribute. Dontdelete ist immer noch da! */
foo = 1;
Foo löschen; // FALSCH
typeof foo; // "Nummer"
/* Aber einer Eigenschaft zuweisen, die nicht existiert,
erstellt diese Eigenschaft mit leeren Attributen (und so ohne dontdelete) */
this.bar = 1;
Bar löschen; // WAHR
typeof bar; // "undefiniert"
Firebug -Verwirrung:
Was passiert in Firebug? Warum können in der Konsole deklarierte Variablen gelöscht werden? Ist dies nicht im Widerspruch zu dem, was wir zuvor gelernt haben? Wie ich bereits sagte, hat der Evalcode eine spezielle Leistung, wenn sie variable Deklarationen haben. In Evaled deklarierte Variablen werden tatsächlich als Attribute ohne das Attribut dontdelete erstellt.
Die Codekopie lautet wie folgt:
eval ('var foo = 1;');
foo; // 1
Foo löschen; // WAHR
typeof foo; // "undefiniert"
Ebenso in ähnlicher Weise, wenn er in Funktionscode aufgerufen wird:
Die Codekopie lautet wie folgt:
(Funktion(){
eval ('var foo = 1;');
foo; // 1
Foo löschen; // WAHR
typeof foo; // "undefiniert"
}) ();
Dies ist die Grundlage für das abnormale Verhalten von Firebug. Der gesamte Text in der Konsole wird eher als Evalcode als als globaler oder Funktionscode ausgeführt. Offensichtlich werden alle hier deklarierten Variablen zu Eigenschaften ohne das Attribut dontdelete, sodass sie alle leicht gelöscht werden können. Wir müssen den Unterschied zwischen dem globalen Code und der Firebug -Konsole verstehen.
Variablen durch eval: löschen:
Dieses interessante Bewertungsverhalten in Verbindung mit einem weiteren Aspekt von ECMascript kann es uns technisch ermöglichen, die Eigenschaften von "nicht tretbar" zu löschen. Eine Sache über Funktionserklärungen ist, dass sie in derselben Ausführungskontext Variablen mit demselben Namen überschreiben können.
Die Codekopie lautet wie folgt:
Funktion x () {}
var x;
typeof x; // "Funktion"
Beachten Sie, wie Funktionserklärungen Priorität erhalten und Variablen mit demselben Namen überschreiben (oder mit anderen Worten dieselben Eigenschaften im Variablenobjekt). Dies liegt daran, dass Funktionserklärungen nach der variablen Deklaration instanziiert werden und sie überschreiben dürfen (variable Deklarationen). Funktionserklärungen ersetzen nicht nur den Wert einer Eigenschaft, sondern ersetzen auch die Eigenschaften dieser Eigenschaft. Wenn wir eine Funktion über Eval deklarieren, sollte diese Funktion die Eigenschaften der ursprünglichen (ersetzten) Eigenschaft durch eigene Eigenschaften ersetzen. Und da Variablen, die über Evaling Decreed -Eigenschaften ohne das Attribut dontdelete deklariert sind, entfernen diese neue Funktion das vorhandene Dontdelete -Attribut aus der Eigenschaft, damit eine Eigenschaft gelöscht werden kann (und offensichtlich ihren Wert auf die neu erstellte Funktion richtet).
Die Codekopie lautet wie folgt:
var x = 1;
/ * Kann nicht löschen, `x` hat dontdelete */
x löschen; // FALSCH
typeof x; // "Nummer"
Eval ('Funktion x () {}');
/ * `x` Eigenschaft jetzt Referenzfunktion und sollte kein dontdelete */haben
typeof x; // "Funktion"
x löschen; // sollte `true` sein
typeof x; // sollte "undefiniert" sein
Leider funktioniert diese "Täuschung" derzeit in keiner Umsetzung. Vielleicht fehlt mir hier etwas, oder vielleicht ist das Verhalten einfach zu dunkel, dass der Implementierer es nicht bemerkt.
Browserkompatibilität:
In der Theorie ist es theoretisch nützlich zu verstehen, wie Dinge funktionieren, aber Praxis ist das Wichtigste. Folgt der Browser den Standards, wenn es darum geht, Variablen/Eigenschaften zu erstellen/zu löschen? Die Antwort lautet: In den meisten Fällen ja.
Ich habe einen einfachen Testsatz für die Testbrowserkompatibilität mit Löschbetreibern geschrieben, einschließlich Tests unter globalem Code, Funktionscode und Evalcode. Der Test -Set prüft, ob der Rückgabewert und die Attributwerte des Löschbetreibers (wie sie sich verhalten sollten) wirklich gelöscht werden. Der Rückgabewert des Löschens ist nicht so wichtig wie sein eigentliches Ergebnis. Wenn Delete true statt falsch zurückgibt, ist dies nicht wichtig, und was wichtig ist, dass Attribute mit dem Attribut dontdelete nicht gelöscht werden und umgekehrt.
Moderne Browser sind im Allgemeinen ziemlich kompatibel. Abgesehen von den zuvor erwähnten Bewertungsfunktionen haben die folgenden Browser alle Testsätze bestanden: Opera 7.54+, Firefox 1.0+, Safari 3.1.2+, Chrome 4+.
Safari 2.x und 3.0.4 haben Probleme beim Löschen von Funktionsparametern; Diese Eigenschaften scheinen ohne Dontdelete erstellt zu werden, sodass sie gelöscht werden können. Safari 2.x hat mehr Probleme - das Löschen von nicht referenzierten Variablen (z. B. Löschen 1) wirft Ausnahmen aus. Funktionserklärungen erzeugen löschbare Eigenschaften (seltsamerweise nicht variable Deklarationen); Variable Deklarationen in EVE werden nicht delet (Funktionserklärungen sind jedoch löschbar).
Ähnlich wie Safari löst Konqueror (3,5, nicht 4,3) eine Ausnahme beim Löschen eines nicht referenzierten Typs (z. B.: Löschen 1) aus und macht die Funktionsvariablen fälschlicherweise löschen.
Anmerkung des Übersetzers:
Ich habe die neuesten Versionen von Chrome, Firefox und IE getestet und beibehalten der Situation, in der alle anderen Pässe mit Ausnahme von 23 und 24 scheitern. Gleichzeitig habe ich UC und einige mobile Browser getestet. Mit Ausnahme des eingebauten Browsers des Nokia E72, in dem auch 15 und 16 ausgeschlossen sind, sind die anderen integrierten Browser meist die gleichen wie Desktop-Browser. Erwähnenswert ist jedoch, dass der eingebaute Browser der Blackberry-Kurve 8310/8900 23 passieren kann, was mich überraschte.
Gecko dontdelete Fehler:
Gecko 1.8.x Browser - Firefox 2.x, Camino 1.x, Seamonkey 1.x usw. - zeigt einen sehr interessanten Fehler. Die explizite Zuordnung einer Eigenschaft entzieht ihre Dontdelete -Eigenschaft, auch wenn diese Eigenschaft durch variable Deklarationen oder Funktionserklärungen erstellt wird.
Die Codekopie lautet wie folgt:
Funktion foo () {}
Foo löschen; // falsch (wie erwartet)
typeof foo; // "Funktion" (wie erwartet)
/ * nun einer Eigenschaft explizit zuweisen *//
this.foo = 1; // fälschlicherweise löscht das Dontdelete -Attribut
Foo löschen; // WAHR
typeof foo; // "undefiniert"
/ * Beachten Sie, dass dies bei der Zuweisung von Eigenschaften implizit */nicht passiert
Funktions bar () {}
Bar = 1;
Bar löschen; // FALSCH
typeof bar; // "Nummer" (obwohl Zuordnung die Eigenschaft ersetzt)
Überraschenderweise hat der Internet Explorer 5.5 - 8 den vollständigen Testsatz bestanden, außer dass das Löschen von nicht referenzierten Typen (z. B. Löschen 1) Ausnahmen (genau wie die alte Safari) auswirft. Es gibt jedoch schwerwiegendere Fehler unter dem IE, was nicht so offensichtlich ist. Diese Fehler beziehen sich auf globales Objekt.
Dh Bugs:
In diesem ganzen Kapitel geht es über Internet Explorer -Fehler? Wow! Es ist unglaublich!
In IE (mindestens IE 6-8) löst der folgende Ausdruck eine Ausnahme aus (wenn sie im globalen Code ausgeführt werden):
this.x = 1;
x löschen; // TypeRror: Objekt unterstützt diese Aktion nicht
Dieser wird auch, aber verschiedene Ausnahmen machen, was die Dinge noch interessanter macht:
var x = 1;
löschen this.x; // TypeRror: Kann 'this.x' nicht löschen
Dies sieht nach IE aus, dass variable Erklärungen im globalen Code keine Attribute für das globale Objekt erstellen. Erstellen von Attributen nach Zuweisung (this.x = 1) und dann durch Löschen von x löschen Sie anschließend einen Fehler. Das Erstellen von Attributen nach Deklaration (var x = 1) und das Löschen von Anschlüssen wirft einen weiteren Fehler auf.
Aber das ist noch nicht alles. Das Erstellen von Eigenschaften durch explizite Aufträge verursacht tatsächlich immer zu Ausnahmen, wenn sie gelöscht werden. Hier gibt es nicht nur Fehler, sondern die erstellten Eigenschaften scheinen das Dontdelete -Attribut zu haben, das natürlich nicht sein sollte.
this.x = 1;
löschen this.x; // TypeRror: Objekt unterstützt diese Aktion nicht
typeof x; // "Nummer" (existiert immer noch, wurde nicht so gelöscht, wie es hätte sein sollen!)
x löschen; // TypeRror: Objekt unterstützt diese Aktion nicht
typeof x; // "Nummer" (wurde nicht wieder gelöscht)
Jetzt würden wir denken, dass unter IE nicht deklarierte Zuordnungen (Eigenschaften für globale Objekte erstellt werden sollten) löschbare Eigenschaften erstellen.
x = 1;
x löschen; // WAHR
typeof x; // "undefiniert"
Wenn Sie diese Eigenschaft jedoch durch diese Referenz im globalen Code löschen (this.x), wird ein ähnlicher Fehler angezeigt.
x = 1;
löschen this.x; // TypeRror: Kann 'this.x' nicht löschen
Wenn wir dieses Verhalten zusammenfassen möchten, scheint es niemals erfolgreich zu sein, Variablen aus dem globalen Code zu delete. Wenn die Eigenschaft in der Frage durch explizite Zuordnung (this.x = 1) erstellt wird, wirft es einen Fehler aus. Wenn die Eigenschaft durch eine nicht deklarierte Zuordnung (x = 1) oder durch eine Deklaration (var x = 1) erstellt wird, wirft es einen weiteren Fehler aus.
Löschen X hingegen sollte nur ein Fehler geworfen werden, wenn die Eigenschaft durch explizite Zuordnung erstellt wird - dies.x = 1. Wenn eine Eigenschaft durch Deklaration (VAR X = 1) erstellt wird, erfolgt die Löschung niemals und die Löschvorstellung gibt die falsche korrekt zurück. Wenn eine Eigenschaft durch nicht deklarierte Zuordnung (x = 1) erstellt wird, funktioniert der Löschvorgang wie erwartet.
Ich habe im September erneut über dieses Problem nachgedacht. Garrett Smith schlug das unter IE vor,
"Das globale variable Objekt wird als Jscript -Objekt implementiert, und das globale Objekt wird vom Host implementiert."
Garrett verwendete den Blogeintrag von Eric Lippert als Referenz.
Wir können diese Theorie mehr oder weniger bestätigen, indem wir einige Tests implementieren. Beachten Sie, dass dieses und das Fenster auf dasselbe Objekt zu zeigen scheinen (wenn wir dem Operator ===), aber das variable Objekt (das Objekt, in dem sich die Funktionserklärung befindet), unterscheidet sich von dem, worauf sich dies zeigt.
Die Codekopie lautet wie folgt:
/ * im globalen Code *//
Funktion getbase () {return this; }
getBase () === this.getBase (); // FALSCH
this.getBase () === this.getBase (); // WAHR
window.getBase () === this.getBase (); // WAHR
window.getBase () === getBase (); // FALSCH
Missverständnis:
Die Schönheit des Verständnisses, warum die Dinge so funktionieren, ist nicht zu unterschätzt. Ich habe einige Missverständnisse über den Löschbetreiber im Internet gesehen. Zum Beispiel erklärt die Antwort auf Stackoverflow (mit überraschend hoher Bewertung) zuversichtlich
"Wenn der Zieloperand keine Objekteigenschaft ist, sollte Löschen betriebsbereit sein."
Nachdem wir den Kern des Löschbetriebsverhaltens verstanden haben, wird der Fehler in dieser Antwort offensichtlich. Löschen unterscheidet nicht zwischen Variablen und Attributen (tatsächlich sind sie für Löschen beide Referenztypen) und kümmern sich tatsächlich nur um Dontdelete -Attribute (und ob die Attribute selbst existieren).
Es ist auch sehr interessant zu sehen, dass verschiedene Missverständnisse sich gegenseitig widerlegen. In demselben Thema schlug eine Person zunächst vor, dass nur Variablen gelöscht werden (dies funktioniert nur, es sei denn, sie wird in Evaly deklariert), während eine andere Person eine Fehlerkorrektur für das Löschen von Variablen im globalen Code, jedoch nicht im Funktionscode verwendet wird.
Seien Sie besonders vorsichtig mit der Erklärung von JavaScript im Internet. Die ideale Methode besteht darin, die Essenz des Problems immer zu verstehen. ;))
Löschen und Hostobjekt (Host -Objekt):
Der Löschalgorithmus ist ungefähr so:
Geben Sie True zurück, wenn der Operand kein Referenztyp ist
Wenn das Objekt kein direktes Attribut dieses Namens hat, geben Sie True zurück (wie wir wissen, kann das Objekt ein aktives Objekt oder ein globales Objekt sein)
Wenn die Eigenschaft existiert, aber das Attribut dontdelete hat, geben Sie false zurück
In anderen Fällen das Attribut löschen und true zurückgeben
Das Verhalten des Löschbetreibers am Host -Objekt ist jedoch unvorhersehbar. Und dieses Verhalten ist eigentlich nicht falsch: (Nach dem Standard) darf das Host -Objekt ein Verhalten für mehrere Operatoren wie Read (interne [[[Get]] -Methode, Schreiben (interne [[Put]] -Methode und Löschen (interne [[[[[[Delete]]] -Methode) implementieren. Diese Gnade für benutzerdefiniertes Verhalten ist das, was das Host -Objekt so verwirrend macht.
Wir haben einige IE -Macken gesehen, bei denen das Löschen spezifischer Objekte (die offensichtlich als Hostobjekte implementiert werden) Fehler werfen. Einige Versionen von Firefox werfen beim Löschen von Fenster. Wenn Operanden Host -Objekte sind, können Sie dem Rückgabewert des Löschens nicht vertrauen. Mal sehen, was in Firefox passiert:
Die Codekopie lautet wie folgt:
/ * "alarm" ist eine direkte Eigenschaft von "Fenster" (wenn wir glauben, "HasownProperty") *//
window.hasownProperty ('alarm'); // WAHR
Fenster löschen.Alert; // WAHR
typeof fenster.alert; // "Funktion"
Fenster löschen. Es wird auf eine Referenz gelöst (so dass es im ersten Schritt nicht wahr zurückgibt). Dies ist eine direkte Eigenschaft eines Fensterobjekts (so dass es im zweiten Schritt nicht wahr zurückgibt). Der einzige Fall, in dem Delete true zurückkehren kann, besteht darin, den vierten Schritt zu erreichen und diese Eigenschaft tatsächlich zu löschen. Diese Eigenschaft wird jedoch nie gelöscht.
Die Moral dieser Geschichte ist: Vertrauen Sie niemals dem Host -Objekt.
ES5 Strict -Modus:
Was bringt uns die strenge Modus -ECMascript5? Es führt nur wenige Einschränkungen ein. Wenn der Ausdruck des Löschoperators eine direkte Referenz auf eine Variable, ein Funktionsparameter oder eine Funktionsbezeichnung ist, wird ein Syntaxfehler geworfen. Wenn die Eigenschaft eine interne Eigenschaft hat [[konfigurierbar]] == Falsch, wird ein Typfehler geworfen.
Die Codekopie lautet wie folgt:
(Funktion (foo) {
"Strikt verwenden"; // Aktivieren Sie den strengen Modus innerhalb dieser Funktion
var bar;
Funktion BAZ () {}
Foo löschen; // syntaxError (beim Löschen von Argumentation)
Bar löschen; // syntaxError (beim Löschen von Variablen)
Baz löschen; // syntaxError (beim Löschen von Variablen mit Funktionserklärung)
/ * `Länge von Funktionsinstanzen hat {[[Konfigurierbar]]: False} */
delete (function () {}). Länge; // TypeRror
}) ();
Darüber hinaus wirft das Löschen von nicht deklarierten Variablen (oder ungelösten Referenzen) auch Syntaxfehler:
"Strikt verwenden";
löschen i_dont_exist; // syntaxError
Die nicht deklarierte Zuordnung verhält sich ähnlich wie nicht deklarierte Variablen im strengen Modus (außer diesem Zeitpunkt wird ein Zitatfehler anstelle eines Syntaxfehlers auferlegt):
"Strikt verwenden";
i_dont_exist = 1; // ReferenzError
Wie Sie jetzt verstehen, sind alle Einschränkungen mehr oder weniger sinnvoll, da das Löschen von Variablen, Funktionserklärungen und Parametern so viel Verwirrung verursachen kann. Anstatt den Löschvorgang still zu ignorieren, nimmt das strenge Muster ein radikaleres und beschreibenderes Maß an.
Zusammenfassen:
Dieser Blog -Beitrag war ziemlich lang, daher werde ich nicht über etwas wie Delete zum Löschen eines Array -Objekts oder darüber sprechen, was es bedeutet. Sie können sich auf die besondere Erklärung des MDC -Artikels beziehen (oder die Standards lesen und Ihre eigenen Experimente durchführen).
Hier finden Sie eine kurze Zusammenfassung der Funktionsweise von Löschvorgängen in JavaScript:
Variablen und Funktionserklärungen sind Eigenschaften von aktiven Objekten oder globalen Objekten
Attribute haben einige Eigenschaften, und das Dontdelete ist das Attribut, das feststellt, ob dieses Attribut gelöscht werden kann.
Variablen und Funktionserklärungen im globalen oder Funktionscode erstellen immer Attribute mit Dontdelete -Attributen.
Funktionsparameter sind immer Attribute des aktiven Objekts und werden von dontdelete begleitet.
Variablen und Funktionen, die im Bewertungscode deklariert sind, erstellen immer Eigenschaften ohne Dontdelete.
Neue Eigenschaften haben keine Attribute, wenn sie erstellt werden (natürlich gibt es auch kein Dontdelete).
Das Host -Objekt darf für sich entscheiden, wie man auf den Löschvorgang reagiert.
Wenn Sie mit dem, was hier beschrieben wird, besser vertraut sein möchten, siehe ECMA-262 3rd Edition-Spezifikation.
Ich hoffe, Sie können diesen Artikel genießen und etwas Neues lernen. Fragen, Vorschläge oder Korrekturen sind willkommen.