lösche ax vs ax = undefined

138

Gibt es einen wesentlichen Unterschied bei beiden?

delete a.x;

vs.

a.x = undefined;

wo

a = {
    x: 'boo'
};

könnte man sagen, dass sie gleichwertig sind?

(Ich berücksichtige keine Dinge wie "V8 verwendet nicht gerne deletebesser" )

bevacqua
quelle
2
Der Löschoperator entfernt eine Eigenschaft vollständig. Wenn Sie eine Eigenschaft auf undefiniert setzen, wird der Wert entfernt. Wenn Sie eine Eigenschaft auf null setzen, wird der Wert in den Wert null geändert. Hier ist ein Perf-Test, wenn Sie möchten
j08691
1
@ j08691 Nit: Der Wert wird nicht entfernt. Es weist undefinedals Wert zu, der immer noch ein ..
Sie sollten darüber sprechen, warum Sie sich dafür interessieren, dann kann die Antwort auf Ihr eigentliches Problem eingehen.
Juan Mendes

Antworten:

181

Sie sind nicht gleichwertig. Der Hauptunterschied ist diese Einstellung

a.x = undefined

bedeutet, dass a.hasOwnProperty("x")immer noch true zurückgegeben wird und daher immer noch in einer for inSchleife und in angezeigt wirdObject.keys()

delete a.x

bedeutet, dass a.hasOwnProperty("x")false zurückgegeben wird

Die Art und Weise, wie sie identisch sind, besteht darin, dass Sie durch Testen nicht feststellen können, ob eine Eigenschaft vorhanden ist

if (a.x === undefined)

Was Sie nicht tun sollten, wenn Sie feststellen möchten, ob eine Eigenschaft vorhanden ist, sollten Sie immer verwenden

// If you want inherited properties
if ('x' in a)

// If you don't want inherited properties
if (a.hasOwnProperty('x'))

Wenn Sie der Prototypenkette folgen (von zzzzBov erwähnt ) delete, können Sie durch Aufrufen die Prototypenkette hochfahren , während beim Festlegen des Werts auf undefiniert nicht nach der Eigenschaft in den verketteten Prototypen gesucht wird. Http://jsfiddle.net/NEEw4/1/

var obj = {x: "fromPrototype"};
var extended = Object.create(obj);
extended.x = "overriding";
console.log(extended.x); // overriding
extended.x  = undefined;
console.log(extended.x); // undefined
delete extended.x;
console.log(extended.x); // fromPrototype

Löschen geerbter Eigenschaften Wenn die Eigenschaft, die Sie löschen möchten, vererbt deletewird, hat dies keine Auswirkungen. Das heißt, es werden deletenur Eigenschaften aus dem Objekt selbst gelöscht, keine geerbten Eigenschaften.

var obj = {x: "fromPrototype"};
var extended = Object.create(obj);
delete extended.x;
console.log(extended.x); // Still fromPrototype

Wenn Sie daher sicherstellen müssen, dass der Wert eines Objekts undefiniert ist deleteund bei der Vererbung der Eigenschaft nicht funktioniert, müssen Sie ihn undefinedin diesem Fall festlegen (überschreiben) . Es sei denn, der Ort, der danach sucht, wird verwendet hasOwnProperty, aber es wäre wahrscheinlich nicht sicher anzunehmen, dass überall, wo es überprüft wird, es verwendet wirdhasOwnProperty

Juan Mendes
quelle
1
"x" in awird auch truemit dem ersteren und falsemit dem letzteren zurückkehren. Die Ausgabe von Object.keyswird auch unterschiedlich sein.
einsamer
Warum sagst du, dass ich nicht nach undefiniert suchen sollte? scheint mir vernünftig genug.
Bevacqua
@Nico Weil das dir nicht sagt, ob eine Eigenschaft existiert. Ich sage nicht, benutze es niemals. Aber wenn Sie nach suchen undefined, können Sie auch einfach nachsehen if (a.x), es sei denn, es ist für Zahlen und 0 ist gültig
Juan Mendes
33

Um die Frage zu paraphrasieren:

Sind delete a.xund a.x = undefinedgleichwertig?

Nein.

Ersteres entfernt den Schlüssel aus der Variablen, letzteres setzt den Schlüssel mit dem Wert von undefined. Dies macht einen Unterschied, wenn Sie über Eigenschaften von Objekten iterieren und wann sie hasOwnPropertyverwendet werden.

a = {
    x: true
};
a.x = undefined;
a.hasOwnProperty('x'); //true
delete a.x;
a.hasOwnProperty('x'); //false

Darüber hinaus wird dies einen signifikanten Unterschied machen, wenn die Prototypenkette beteiligt ist.

function Foo() {
    this.x = 'instance';
}
Foo.prototype = {
    x: 'prototype'
};
a = new Foo();
console.log(a.x); //'instance'

a.x = undefined;
console.log(a.x); //undefined

delete a.x;
console.log(a.x); //'prototype'
zzzzBov
quelle
2
+1 Großartiger Punkt, um deletezuzulassen, dass es die Prototypenkette hinaufgeht
Juan Mendes
4

Wenn a.xes sich um eine Setterfunktion handelt, a.x = undefinedwird die Funktion aufgerufen, während die Funktion delete a.xnicht aufgerufen wird.

martin770
quelle
3

Ja, da gibt es einen Unterschied. Wenn Sie delete a.xdas x verwenden, ist es keine Eigenschaft von a mehr, aber wenn Sie es verwenden a.x=undefined, ist es eine Eigenschaft, aber sein Wert ist undefiniert.


quelle
2

Die Namen sind etwas verwirrend. a.x = undefinedSetzt nur die Eigenschaft auf undefined, aber die Eigenschaft ist immer noch da:

> var a = {x: 3};
> a.x = undefined;
> a.constructor.keys(a)
["x"]

delete löscht es tatsächlich:

> var a = {x: 3};
> delete a.x;
> a.constructor.keys(a)
[]
Mixer
quelle
1

Diese REPL vom Knoten sollte den Unterschied veranschaulichen.

> a={ x: 'foo' };
{ x: 'foo' }
> for (var i in a) { console.log(i); };
x
undefined
> a.x=undefined;
undefined
> for (var i in a) { console.log(i); };
x
undefined
> delete a.x;
true
> for (var i in a) { console.log(i); };
undefined
Kojiro
quelle
1

Ich bin sicher, Sie können den Unterschied zwischen var o1 = {p:undefined};und sehen var o2 = {};.

In beiden Fällen o.pwird es undefinedaber im ersten Fall sein, weil das der Wert ist und im zweiten Fall, weil es keinen Wert gibt .

deleteist der Operator, mit dem Sie von o1(oder einem anderen Objekt, dem eine pEigenschaft zugewiesen ist ) auf o2diese Weise gelangen : delete o1.p;.

Die umgekehrte Operation wird durchgeführt, indem undefinedder Eigenschaft einfach ein Wert zugewiesen wird ( in diesem Beispiel könnte es sich jedoch um etwas anderes handeln) o1.p = undefined;.

Also nein , sie sind nicht gleichwertig.


delete o.p; werden

  • Entfernen Sie die Eigenschaft paus dem Objekt, falls vorhanden

  • sonst nichts tun

o.p = undefined; werden

  • Fügen Sie pdem Objekt eine Eigenschaft hinzu , falls noch keine vorhanden ist, und setzen Sie den Wert aufundefined

  • Ändern Sie einfach den Wert der Eigenschaft, wenn das Objekt ihn bereits hat


Aus Sicht der Leistung deleteist dies schlecht, da dadurch die Struktur des Objekts geändert wird (genau wie beim Hinzufügen einer neuen Eigenschaft, wenn Sie diese nicht im Konstruktor initialisiert haben).

Wenn Sie den Wert so einstellen, dass auch undefinedder Inhalt freigegeben wird, ohne die Struktur zu ändern.

xavierm02
quelle
1

Objekt ist einfach eine Baumdarstellung, dh im Speicher zeigt der Stamm auf verschiedene Speicherorte, an denen Schlüssel dieses Objekts gespeichert sind. und dieser Ort zeigt auf einen anderen Ort, an dem der tatsächliche Wert dieses Schlüssels gespeichert ist, oder auf Orte, an denen die untergeordneten Schlüssel gespeichert sind, oder auf Orte, an denen die Array-Werte gespeichert sind.

Wenn Sie einen Schlüssel mit delete aus einem Objekt löschen, wird tatsächlich die Verknüpfung zwischen diesem Schlüssel und seinem übergeordneten Objekt gelöscht, und die Speicherorte des Schlüssels und sein Wert werden freigegeben, um weitere Informationen zu speichern.

Wenn Sie versuchen, einen Schlüssel zu löschen, indem Sie undefined als Wert festlegen, legen Sie nur seinen Wert fest und löschen diesen Schlüssel nicht. Dies bedeutet, dass der Speicherort des Schlüssels weiterhin mit dem übergeordneten Objekt und dem Wert verknüpft ist, wenn der Schlüssel nicht definiert ist.

Die Verwendung von undefined anstelle von delete keyword ist eine schlechte Vorgehensweise, da der Speicherort dieses Schlüssels nicht freigegeben wird.

Selbst wenn der Schlüssel nicht vorhanden ist und Sie ihn als undefiniert festlegen, wird dieser Schlüssel mit Wert erstellt undefined.

z.B

var a = {};
a.d = undefined;
console.log(a); // this will print { d: undefined }

delete kann nicht mit geerbten Eigenschaften bearbeitet werden, da diese Eigenschaft nicht Teil dieses untergeordneten Objekts ist.

Laxmikant Dange
quelle
1
Beachten Sie, dass neuere Engines es vorziehen, keine Schlüssel zu löschen, da die Engine dann eine neue Klasse dafür erstellen und aktualisieren muss, wo immer auf die "Klasse" verwiesen wurde.
Juan Mendes
@ JuanMendes, können Sie bitte eine Referenz geben.
Laxmikant Dange
3
Siehe Beeinflusst die Verwendung des Schlüsselworts delete die v8-Optimierung eines Objekts? TL; DR as a general rule of thumb, using 'delete' makes thing slower.und developer.google.com/v8/design To reduce the time required to access JavaScript properties, V8 does not use dynamic lookup to access properties. Instead, V8 dynamically creates hidden classes behind the scenes. In V8, an object changes its hidden class when a new property is added. und schließlich smashingmagazine.com/2012/11/…
Juan Mendes
1

Wenn ich ein Array anstelle eines Objekts verwende, kann ich zeigen, dass das Löschen weniger Heapspeicher als undefiniert benötigt.

Dieser Code wird beispielsweise nicht beendet:

let y = 1;
let ary = [];
console.log("Fatal Error Coming Soon");
while (y < 4294967295)
{
    ary.push(y);
    ary[y] = undefined;
    y += 1;
}
console(ary.length);

Es erzeugt diesen Fehler:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory.

Wie Sie sehen, undefinednimmt der Heap-Speicher tatsächlich in Anspruch.

Wenn Sie jedoch auch deletedas ary-Element verwenden (anstatt es nur auf zu setzen undefined), wird der Code langsam beendet:

let x = 1;
let ary = [];
console.log("This will take a while, but it will eventually finish successfully.");
while (x < 4294967295)
{
    ary.push(x);
    ary[x] = undefined;
    delete ary[x];
    x += 1;
}
console.log(`Success, array-length: ${ary.length}.`);

Dies sind extreme Beispiele, aber sie weisen darauf hin, deletedass ich nirgendwo jemanden erwähnt habe.

Lonnie Best
quelle