Wie deaktiviere ich eine JavaScript-Variable?

592

Ich habe eine globale Variable in JavaScript (eigentlich eine windowEigenschaft, aber ich denke nicht, dass es wichtig ist), die bereits von einem vorherigen Skript gefüllt wurde, aber ich möchte nicht, dass ein anderes Skript, das später ausgeführt wird, seinen Wert sieht oder dass es gerade ist definiert.

Ich habe es gesetzt some_var = undefinedund es funktioniert zum Zweck des Testens, typeof some_var == "undefined"aber ich denke wirklich nicht, dass es der richtige Weg ist, dies zu tun.

Was denken Sie?

Guss
quelle

Antworten:

454

Der deleteOperator entfernt eine Eigenschaft aus einem Objekt. Eine Variable kann nicht entfernt werden. Die Antwort auf die Frage hängt also davon ab, wie die globale Variable oder Eigenschaft definiert ist.

(1) Wenn es mit erstellt wurde var, kann es nicht gelöscht werden.

Zum Beispiel:

var g_a = 1; //create with var, g_a is a variable 
delete g_a; //return false
console.log(g_a); //g_a is still 1

(2) Wenn es ohne erstellt wird var, kann es gelöscht werden.

g_b = 1; //create without var, g_b is a property 
delete g_b; //return true
console.log(g_b); //error, g_b is not defined

Technische Erklärung

1. Verwenden von var

In diesem Fall wird die Referenz g_ain der ECMAScript-Spezifikation " VariableEnvironment " erstellt, die an den aktuellen Bereich angehängt ist. Dies kann der Kontext für die varFunktionsausführung sein, wenn eine Funktion verwendet wird (obwohl dies etwas komplizierter werden kann) Wenn Sie dies berücksichtigen let) oder im Fall von "globalem" Code wird die VariableEnvironment (häufig window) an das globale Objekt angehängt .

Verweise in der Variablenumgebung sind normalerweise nicht löschbar - der in ECMAScript 10.5 beschriebene Prozess erklärt dies ausführlich, reicht jedoch aus, um zu sagen, dass evalVariablen, mit denen die meisten browserbasierten Entwicklungskonsolen deklariert varsind, nicht ausgeführt werden können, sofern Ihr Code nicht in einem Kontext ausgeführt wird (den die meisten browserbasierten Entwicklungskonsolen verwenden) gelöscht werden.

2. Ohne zu verwenden var

Beim Versuch, einem Namen einen Wert zuzuweisen, ohne das varSchlüsselwort zu verwenden, versucht Javascript, die benannte Referenz in der ECMAScript-Spezifikation " LexicalEnvironment " zu finden. Der Hauptunterschied besteht darin, dass LexicalEvironments verschachtelt sind - das heißt, LexicalEnvironment hat ein übergeordnetes Element ( Was die ECMAScript-Spezifikation als "Referenz für die äußere Umgebung" bezeichnet) und wenn Javscript die Referenz in einer LexicalEenvironment nicht findet , wird sie in der übergeordneten LexicalEnvironment angezeigt (wie in 10.3.1 und 10.2.2.1 beschrieben ). Die LexicalEnvironment der obersten Ebene ist die " globale Umgebung"", und das ist an das globale Objekt gebunden, da seine Referenzen die Eigenschaften des globalen Objekts sind. Wenn Sie also versuchen, auf einen Namen zuzugreifen, der nicht mit einem varSchlüsselwort im aktuellen Bereich oder einem äußeren Bereich deklariert wurde, ruft Javascript schließlich eine Eigenschaft ab des windowObjekts als dieser Referenz zu dienen. wie wir bereits gelernt haben, Eigenschaften auf Objekte gelöscht werden können.

Anmerkungen

  1. Es ist wichtig, sich daran zu erinnern, dass varDeklarationen "gehisst" werden - dh sie werden immer als am Anfang des Bereichs betrachtet betrachtet, in dem sie sich befinden - obwohl nicht die Wertinitialisierung, die in einer varAnweisung durchgeführt werden kann -, die dort belassen wird, wo sie ist . Im folgenden Code abefindet sich also eine Referenz aus der Variablenumgebung und nicht die windowEigenschaft, und ihr Wert befindet sich 10am Ende des Codes:

    function test() { a = 5; var a = 10; }

  2. Die obige Diskussion ist, wenn "strikter Modus" nicht aktiviert ist. Suchregeln sind etwas anders, wenn der "strenge Modus" verwendet wird, und lexikalische Verweise, die ohne "strengen Modus" in Fenstereigenschaften aufgelöst worden wären, führen im "strengen Modus" zu Fehlern bei "nicht deklarierten Variablen". Ich habe nicht wirklich verstanden, wo dies angegeben ist, aber wie sich Browser verhalten.

Dayong
quelle
8
Was Sie gesagt haben, ist ein weit verbreitetes Missverständnis, aber tatsächlich falsch - in Javascript gibt es keine "globalen Variablen". Variablen, die ohne expliziten Bereich definiert sind (z. B. varaußerhalb einer Funktion), sind Eigenschaften des "globalen Objekts", das in Webbrowsern verwendet wird window. Also - var a = 1; delete window.a; console.log(a);löscht die Variable erfolgreich und bewirkt, dass in der letzten Zeile ein Referenzfehler ausgegeben wird.
Guss
7
@Guss, Ihr Code var a = 1; delete window.a; console.log(a);zeigt 1.
Dayong
5
Ich verwende Google Chrome v36. Ich habe auf anderen Browsern getestet. Es sieht so aus, als wäre es kein konsistenter Cross-Browser. Chrome und Opera zeigten 1 an, während Firefox, Safari und IE 11 auf meinem Computer einen Fehler angaben.
Dayong
3
Ok, mein Fehler. Siehe ecma-international.org/ecma-262/5.1/#sec-10.5 (Unterpunkte 2 und 8.c.ii): Wenn ich meinen Test in der Entwicklerkonsole ausführe, wird er im Allgemeinen als "eval context" betrachtet (obwohl dies möglicherweise der Fall ist nicht in Chrome), daher wird ein Fehler ausgelöst. Der gleiche Code im globalen Kontext eines realen Dokuments wird 1in allen Browsern korrekt ausgegeben . Ihre Codebeispiele laufen in realen Dokumenten und sind korrekt. Ich habe Ihre Antwort als richtig ausgewählt, aber ich würde es begrüßen, wenn Sie sie bearbeiten können, um Erklärungen window.a = 1; delete window.a;und möglicherweise den Mechanismus einzuschließen. Ich kann das auch, wenn es Ihnen nichts ausmacht.
Guss
2
@KlaiderKlai ja. Variablen mit Funktionsbereich werden jedes Mal erstellt und zerstört, wenn die Funktion ausgeführt wird. Wahrscheinlich ist die Schließung eine Ausnahme.
Dayong
278

Die Antwort von @ scunlife wird funktionieren, aber technisch sollte es sein

delete window.some_var; 

Löschen soll ein No-Op sein, wenn das Ziel keine Objekteigenschaft ist. z.B,

(function() {
   var foo = 123;
   delete foo; // wont do anything, foo is still 123
   var bar = { foo: 123 };
   delete bar.foo; // foo is gone
}());

Da globale Variablen jedoch tatsächlich Mitglieder des Fensterobjekts sind, funktioniert dies.

Wenn Prototypketten beteiligt sind, wird die Verwendung von delete komplexer, da nur die Eigenschaft aus dem Zielobjekt und nicht aus dem Prototyp entfernt wird. z.B,

function Foo() {}
Foo.prototype = { bar: 123 };
var foo = new Foo();
// foo.bar is 123
foo.bar = 456;
// foo.bar is now 456
delete foo.bar;
// foo.bar is 123 again.

Also sei vorsichtig.

EDIT: Meine Antwort ist etwas ungenau (siehe "Missverständnisse" am Ende). Der Link erklärt alle wichtigen Details, aber die Zusammenfassung ist, dass es große Unterschiede zwischen Browsern geben kann und abhängig von dem Objekt, aus dem Sie löschen. delete object.somePropsollte im Allgemeinen sicher sein, solange object !== window. Ich würde es immer noch nicht verwenden, um Variablen zu löschen, mit vardenen deklariert wurde, obwohl Sie dies unter den richtigen Umständen können.

Noah
quelle
14
danke @jedierikb für den Link zu diesem interessanten Artikel. Genauer gesagt ist dieser Teil < perfektionkills.com/understanding-delete/#misconceptions > dieses Artikels, in dem der Autor feststellt, dass Noahs Aussage "Löschen soll ein No-Op sein" ziemlich ungenau ist, zusammen mit einer ausgezeichneten Erklärung, warum es ungenau ist . (Erschieße nicht den Boten!)
Rob Wells
2
In Bezug auf den letzten Satz der überarbeiteten Antwort können Sie Variablen, mit vardenen deklariert wurde, nur löschen, wenn die Variable mit deklariert wurde eval.
Stephen Booher
1
In diesem Fall scheint die delete-Anweisung überhaupt nichts zu bewirken. Was ist denn hier los?
Anderson Green
@ AndersonGreen - Entkalkte globale Variablen werden mit dem DontDelete- Flag erstellt und können daher nicht gelöscht werden. Dieser Code verhält sich genau wie erwartet.
RobG
35

Wenn Sie die Variable implizit ohne deklarieren var, ist der richtige Weg, sie zu verwenden delete foo.

Wenn Sie jedoch versuchen, dies in einem Vorgang wie dem Hinzufügen von a zu verwenden, ReferenceErrorwird nach dem Löschen a ausgelöst, da Sie einem nicht deklarierten, nicht definierten Bezeichner keine Zeichenfolge hinzufügen können. Beispiel:

x = 5;
delete x
alert('foo' + x )
// ReferenceError: x is not defined

In einigen Situationen kann es sicherer sein, es false, null oder undefined zuzuweisen, damit es deklariert wird und diese Art von Fehler nicht auslöst.

foo = false

Beachten Sie, dass in ECMAScript null, false, undefined, 0, NaN, oder ''würde alles bewerten zu false. Stellen Sie nur sicher, dass Sie nicht den !==Operator verwenden, sondern stattdessen !=bei der Typprüfung auf Boolesche Werte und Sie möchten keine Identitätsprüfung (so nullwürde == falseund false == undefined).

Beachten Sie auch, dass deletekeine Referenzen "gelöscht" werden, sondern nur Eigenschaften direkt auf dem Objekt, z.

bah = {}, foo = {}; bah.ref = foo;

delete bah.ref;
alert( [bah.ref, foo ] )
// ,[object Object] (it deleted the property but not the reference to the other object)

Wenn Sie eine Variable mit deklariert haben, varkönnen Sie sie nicht löschen:

(function() {
    var x = 5;
    alert(delete x)
    // false
})();

In Rhino:

js> var x
js> delete x
false

Sie können auch einige vordefinierte Eigenschaften wie Math.PI:

js> delete Math.PI
false

Es gibt einige merkwürdige Ausnahmen deletewie bei jeder Sprache. Wenn Sie sich genug darum kümmern, sollten Sie lesen:

meder omuraliev
quelle
Vielen Dank für die vollständige Antwort mit allen Details. Ich habe es dafür markiert, aber ich habe Noahs Antwort akzeptiert, weil ich glaube, dass für eine einfache Frage Kürze wichtiger ist als Vervollständigung. Nochmals vielen Dank für die großartige Arbeit, die Sie an dieser Antwort geleistet haben.
Guss
30
some_var = null;

//or remove it..
delete some_var;
scunliffe
quelle
11
Dies funktioniert nicht, wenn der Umfang dieses Codes eine Funktion ist. Die richtige Lösung finden Sie in der Antwort von @ noah.
Roatin Marth
1
Danke für die Antwort, aber ich habe Noahs Antwort akzeptiert, weil sie die Fallstricke von besser erklärt delete.
Guss
3
Keine Sorge ... Ich gab eine "schnelle und schmutzige" einfache Antwort - @noah fügte alle Details für die "anderen" Fälle hinzu, daher verdient er auch Anerkennung. ;-)
Scunliffe
7
Das ist nicht richtig. deletefunktioniert nur für eine Immobilie. Das Einstellen nullder Variablen ist noch vorhanden.
Derek 23 會 功夫
1
Diese Antwort ist gut genug für den wahrscheinlichsten Fall, in dem Sie mit "if (some_var) {..}"
BearCode
16

TLDR: einfach definierte Variablen (ohne var, let, const) konnte mit gelöscht werden delete. Wenn Sie ,, verwenden var, letkonnten constsie weder mit deletenoch mit gelöscht werden Reflect.deleteProperty.

Chrome 55:

simpleVar = "1";
"1"
delete simpleVar;
true
simpleVar;
VM439:1 Uncaught ReferenceError: simpleVar is not defined
    at <anonymous>:1:1
(anonymous) @ VM439:1
var varVar = "1";
undefined
delete varVar;
false
varVar;
"1"
let letVar = "1";
undefined
delete letVar;
true
letVar;
"1"
const constVar="1";
undefined
delete constVar;
true
constVar;
"1"
Reflect.deleteProperty (window, "constVar");
true
constVar;
"1"
Reflect.deleteProperty (window, "varVar");
false
varVar;
"1"
Reflect.deleteProperty (window, "letVar");
true
letVar;
"1"

FF Nightly 53.0a1 zeigt das gleiche Verhalten.

Serj.by
quelle
Ihre Antwort ist technisch korrekt, sodass Sie einen Punkt erhalten, aber alles, was Sie geschrieben haben, wird von der ausgewählten Antwort mit viel mehr Details und Verweisen auf die ECMAScript-Spezifikationen abgedeckt. In Zukunft wäre es hilfreich, die vorhandene Antwort vor dem Posten zu überprüfen.
Guss
5
Einverstanden. Aber dort nur varFall erwähnt. Wie war es für mich zu testen und mit anderen teilen interessant letund constauch Fälle. Vielen Dank für den Hinweis. Ich werde versuchen, das nächste Mal genauer zu sein.
Serj.by
4

ECMAScript 2015 bietet Reflect API. Es ist möglich, Objekteigenschaften mit Reflect.deleteProperty () zu löschen :

Reflect.deleteProperty(myObject, 'myProp');
// it is equivalent to:
delete myObject.myProp;
delete myObject['myProp'];

So löschen Sie die Eigenschaft eines globalen windowObjekts:

Reflect.deleteProperty(window, 'some_var');

In einigen Fällen können Eigenschaften nicht gelöscht werden (wenn die Eigenschaft nicht konfigurierbar ist), und dann kehrt diese Funktion zurück false(sowie der Löschoperator ). In anderen Fällen Rückgabe true:

Object.defineProperty(window, 'some_var', {
    configurable: false,
    writable: true,
    enumerable: true,
    value: 'some_val'
});

var frozen = Object.freeze({ myProperty: 'myValue' });
var regular = { myProperty: 'myValue' };
var blank = {};

console.log(Reflect.deleteProperty(window, 'some_var')); // false
console.log(window.some_var); // some_var

console.log(Reflect.deleteProperty(frozen, 'myProperty')); // false
console.log(frozen.myProperty); // myValue

console.log(Reflect.deleteProperty(regular, 'myProperty')); // true
console.log(regular.myProperty); // undefined

console.log(Reflect.deleteProperty(blank, 'notExistingProperty')); // true
console.log(blank.notExistingProperty); // undefined

Im strengen Modus gibt es einen Unterschied zwischen deletePropertyFunktion und deleteBediener:

'use strict'

var frozen = Object.freeze({ myProperty: 'myValue' });

Reflect.deleteProperty(frozen, 'myProperty'); // false
delete frozen.myProperty;
// TypeError: property "myProperty" is non-configurable and can't be deleted
madox2
quelle
4

Variablen haben im Gegensatz zu einfachen Eigenschaften das Attribut [[Konfigurierbar]] , was bedeutet, dass es unmöglich ist, eine Variable über den Löschoperator zu entfernen . Es gibt jedoch einen Ausführungskontext, auf den sich diese Regel nicht auswirkt. Dies ist der Bewertungskontext : Das Attribut [[Konfigurierbar]] ist für Variablen nicht festgelegt.

Eldiyar Talantbek
quelle
3

Beachten Sie zusätzlich zu dem, was alle geschrieben haben, auch, dass deleteBoolesche Werte zurückgegeben werden. Es kann Ihnen sagen, ob der Löschvorgang erfolgreich war oder nicht.

Beim Testen auf Chrome war alles außer letlöschbar. bei der deleteRückgabe wurden truesie tatsächlich entfernt:

implicit_global = 1;
window.explicit_global = 1;
function_set = function() {};
function function_dec() { };
var declared_variable = 1;
let let_variable = 1;

delete delete implicit_global; // true, tested on Chrome 52
delete window.explicit_global; // true, tested on Chrome 52
delete function_set; // true, tested on Chrome 52
delete function_dec; // true, tested on Chrome 52
delete declared_variable; // true, tested on Chrome 52
delete let_variable; // false, tested on Chrome 78
Oriadam
quelle
Es ist nicht immer richtig. Besonders in Chrome. Firefox gibt alles korrekt zurück. In keinem anderen Browser getestet. Was letvars und constvars betrifft, wird true zurückgegeben, was bedeuten sollte, dass die Variable gelöscht wurde, dies jedoch nicht. Sie können es sowohl in Chrome als auch in FF einchecken. FF scheint korrekte Werte zurückzugeben, Chrome jedoch nicht. Ich bin mir also nicht sicher, ob Sie sich wirklich darauf verlassen können. Mal sehen:let letVar = "1"; undefined delete letVar; true letVar "1" typeof letVar; "string" const constVar="1"; undefined delete constVar; true constVar; "1" typeof constVar; "string"
Serj.by
1
Wie jedierikb unten erwähnt gibt es perfekte Artikel von kangax perfectionkills.com/understanding-delete , dass vor allem beschreibt , warum und wie deleteBetreiber funktioniert. Aber es beschreibt nicht, warum buchstäblich eine Situation mit Funktionen entgegengesetzt ist. Schade. In Bezug auf Variablen scheinen die Dinge jedoch viel klarer zu sein.
Serj.by
2

Sie können eine Variable nicht löschen, wenn Sie sie zum Zeitpunkt der ersten Verwendung (mit var x;) deklariert haben. Wenn Ihre Variable x jedoch zum ersten Mal ohne Deklaration im Skript angezeigt wurde, können Sie den Löschoperator (delete x;) verwenden. Ihre Variable wird gelöscht, ähnlich wie beim Löschen eines Elements eines Arrays oder beim Löschen einer Eigenschaft eines Objekts .

Satyapriya Mishra
quelle
1

Ich bin etwas verwirrt. Wenn Sie lediglich möchten, dass ein Variablenwert nicht an ein anderes Skript übergeben wird, müssen Sie die Variable nicht aus dem Bereich löschen. Machen Sie die Variable einfach ungültig und prüfen Sie dann explizit, ob sie null ist oder nicht. Warum sollten Sie sich die Mühe machen, die Variable aus dem Gültigkeitsbereich zu löschen? Welchen Zweck hat dieser Server, den das Aufheben nicht kann?

foo = null;
if(foo === null) or if(foo !== null)
designdrumm
quelle
Voraussetzung ist, dass das Auftragsskript, das nicht unter meiner Kontrolle steht, nicht erkennt, dass die Variable vorhanden ist. Speziell für den OP-Fall hat das Zielskript ein Verhalten für den nullWert, den ich nicht auslösen möchte.
Guss
Während der Erstellung dieser Frage wurde kein "Backend" missbraucht. Dies sind nur ein paar Skripte auf einer Website, auf die ich außer diesem einen Skript keine Kontrolle habe.
Guss
Befinden sich beide Skripte im selben Dokument oder in separaten Dokumenten, die das andere zum Laden aufruft? Sie haben das Bestellskript und das Zielskript erwähnt. Wenn es darum geht, dass eine Variable über eine get / post-Variable an ein anderes Skript übergeben wird, würde ich sie im Backend löschen, bevor Javascript sie in die Hände bekommt. Ein Beispiel dafür in PHP wäre so etwas wie. <?php if(isset($_POST['somevariable']) unset($_POST['somevariable']); if(isset($_GET['somevariable']) unset($_GET['somevariable']); ?>
Designdrumm
Aha. Nun, wenn es Checks and Balances für Null gibt, dann scheint es logischer zu sein, es auf einen Wert zu setzen, mit dem das Zielskript nichts zu tun hat, als eine Variable aus dem Gültigkeitsbereich zu löschen, aber Sie möchten Ihre Antwort haben, also lasse ich das Pferd liegen. Vielen Dank für Ihre Antworten.
Designdrumm
Eine kurze Frage. Wird es jemals ein Skript geben, das nach Ihrem aufgerufen wird und nicht unter Ihrer Kontrolle steht, aber diese Variable weiterhin benötigt? Wenn ja, ist das Löschen der Variablen aus dem Bereich eine schlechte Idee.
Designdrumm