Wie gefährlich ist es in JavaScript wirklich anzunehmen, dass undefiniert nicht überschrieben wird?

86

Jedes Mal , wenn jemand erwähnt die Prüfung gegen undefined, es ist darauf hingewiesen , dass undefinedkein Schlüsselwort ist , so kann es eingestellt werden"hello" , so dass Sie verwenden sollen typeof x == "undefined" , statt. Das kommt mir lächerlich vor. Niemand würde das jemals tun, und wenn sie es tun würden, wäre es Grund genug, niemals einen Code zu verwenden, den sie geschrieben haben ... richtig?

Ich fand ein Beispiel von jemandem, der aus Versehen gesetzt undefinedzu null, und dies wurde als Grund gegeben zu vermeiden , unter der Annahme , dass undefinednicht überschrieben wird. Aber wenn sie das getan hätten, wäre der Fehler unentdeckt geblieben, und ich sehe nicht, wie das besser ist.

In C ++ ist sich jeder bewusst, dass es legal ist zu sagen #define true false, aber niemand rät Ihnen jemals, es zu vermeiden trueund 0 == 0stattdessen zu verwenden. Sie gehen einfach davon aus, dass niemand jemals groß genug sein würde, um das zu tun, und wenn doch, vertrauen Sie ihrem Code nie wieder.

Hat dies jemals jemanden gebissen, dem jemand anderes undefined(absichtlich) zugewiesen wurde, und es hat Ihren Code gebrochen, oder ist dies eher eine hypothetische Bedrohung? Ich bin bereit, mein Risiko einzugehen, um meinen Code geringfügig lesbarer zu machen. Ist das eine wirklich schlechte Idee?

Um es noch einmal zu wiederholen, ich frage nicht , wie ich mich vor neu zugewiesenen undefinierten schützen soll. Ich habe diese Tricks schon 100 Mal geschrieben. Ich frage, wie gefährlich es ist, diese Tricks nicht anzuwenden.

Cosmologicon
quelle
7
Ich würde es gerne tun, aber ich habe nicht das Gefühl, dass eine der drei gegebenen Antworten die Frage gut beantwortet. Ich habe versucht klar zu machen, dass ich nicht um eine Wiederholung der Antworten gebeten habe, mit denen ich verlinkt habe, aber das habe ich immer noch bekommen. Wenn es als gauche angesehen wird, eine Antwort nicht anzunehmen, auch wenn es nicht das ist, was ich gefragt habe, lass es mich wissen und ich werde weitermachen und eine annehmen!
Cosmologicon
1
Ich denke jedoch, dass hier alle Fakten dargelegt sind. Sie wollen also stattdessen eine subjektive Antwort oder Meinung, was nur zu Meinungsverschiedenheiten führt. Dies ist der Grund, warum der Ausdruck "Best Practice" in Fragetiteln nicht zulässig ist. Sie sind die einzige Person, die wissen kann, wie gefährlich es in Ihrem Szenario ist. Und wenn Sie eine beliebte Bibliothek schreiben, in der Sie nicht alle 'Variablen' steuern, scheint der Wrapper function (undefined) {} ​​eine hervorragende Antwort zu sein. Warum nicht benutzen und diese Antwort akzeptieren?
Shannon
4
Wenn jemand die über jemanden Neudefinition besorgt undefined, sollten Sie mehr über jemanden Neudefinition kümmern XMLHttpRequest, oder alert. Alle Funktionen, die wir verwenden, windowkönnten neu definiert worden sein. Und wenn Sie sich nur Sorgen machen, dass ein Mitarbeiter dies versehentlich tut, warum sollten Sie ihm dann vertrauen, dass er es nicht tut window.addEventListener = "coolbeans"? Die Antwort ist, sich darüber keine Sorgen zu machen. Wenn jemand böswillig JS in Ihre Seite injiziert, werden Sie trotzdem abgespritzt. Die Arbeiten an verhindern , dass aus geschieht in erster Linie.
Chris Middleton

Antworten:

56

Nein, das habe ich nie. Dies liegt hauptsächlich daran, dass ich auf modernen Browsern entwickle, die größtenteils ECMAScript 5-kompatibel sind. Der ES5-Standard schreibt vor, dass dies undefinedjetzt nur noch lesbar ist. Wenn Sie den strengen Modus verwenden (sollten Sie), wird ein Fehler ausgegeben, wenn Sie versehentlich versuchen, ihn zu ändern.

undefined = 5;
alert(undefined); // still undefined
'use strict';
undefined = 5; // throws TypeError

Was Sie nicht tun sollten , ist Ihr eigenes Ziel zu erstellen, veränderlich undefined:

(function (undefined) {
    // don't do this, because now `undefined` can be changed
    undefined = 5;
})();

Konstante ist in Ordnung. Immer noch unnötig, aber in Ordnung.

(function () {
    const undefined = void 0;
})();
Ry-
quelle
Ihre erste Anweisung stellt nur sicher, dass Sie während der Entwicklung nicht versehentlich undefiniert überschreiben. Sie stellt dennoch die gleiche Bedrohung dar, wenn Sie mit anderem Code auf Clientcomputern ausgeführt werden.
Bennedich
1
@bennedich: Ich weiß, ich habe gesagt, ich bin nie auf dieses Problem gestoßen, aber hier ist, was Sie tun sollten .
Ry-
1
@bennedich Haben Sie nicht die gleiche Chance, versehentlich eine andere Variable zu überschreiben?
Ates Goral
40

Kein richtiger Code kann so etwas tun. Aber Sie können nie wissen, was ein Möchtegern-Smart-Entwickler oder ein Plugin / eine Bibliothek / ein Skript, das Sie verwenden, getan hat. Auf der anderen Seite ist dies äußerst unwahrscheinlich und moderne Browser erlauben undefinedüberhaupt kein Überschreiben. Wenn Sie also einen solchen Browser für die Entwicklung verwenden, werden Sie schnell feststellen, ob Code versucht, ihn zu überschreiben.


Und obwohl Sie nicht danach gefragt haben - viele Leute werden diese Frage wahrscheinlich finden, wenn sie nach dem allgemeineren undefinedProblem suchen, wie man sich vor einer Neudefinition schützt. Deshalb werde ich das trotzdem beantworten:

Es gibt einen sehr guten Weg, um eine wirklich undefinierte zu erhalten, undefined egal wie alt der Browser ist:

(function(undefined) {
    // your code where undefined is undefined
})();

Dies funktioniert, weil immer ein Argument angegeben wird, das nicht angegeben ist undefined. Sie können dies auch mit einer Funktion tun, die einige echte Argumente akzeptiert, z. B. wenn Sie jQuery verwenden. Es ist normalerweise eine gute Idee, auf diese Weise eine gesunde Umgebung zu gewährleisten:

(function($, window, undefined) {
    // your code where undefined is undefined
})(jQuery, this);

Dann können Sie sicher sein, dass innerhalb dieser anonymen Funktion die folgenden Dinge zutreffen:

  • $ === jQuery
  • window === [the global object]
  • undefined === [undefined].

Beachten Sie jedoch, dass manchmal typeof x === 'undefined'tatsächlich erforderlich ist : Wenn die Variable xnie auf einen Wert gesetzt (entgegen zu sein gewesen Satz zu undefined), das Lesen xin einer anderen Art und Weise, wie if(x === undefined)einen Fehler werfen. Dies gilt jedoch nicht für Objekteigenschaften. Wenn Sie also wissen, dass yes sich immer um ein Objekt handelt, if(y.x === undefined)ist dies absolut sicher.

DiebMaster
quelle
2
Ihre Aussage, dass xkein Wert festgelegt wurde, ist nicht ganz richtig (siehe jsfiddle.net/MgADz ). Es ist eher so, als ob es wirklich nicht definiert ist (siehe jsfiddle.net/MgADz/1 ).
Ry-
7
Nochmals, wenn jemand versehentlich sagt, undefined = someVariabledass dies ein Fehler ist und Sie möchten , dass die Dinge kaputt gehen. Zumindest tue ich das.
Cosmologicon
2
Ich habe mit einer Codebasis gearbeitet, die ein minimiertes Legacy-Skript hatte, das undefiniert überschrieb. Wir hatten weder Zeit noch Budget, um das Skript neu zu schreiben. Dies ist ein Beispiel, in dem der Typ x == "undefiniert" erforderlich war. Es ist nicht so seltsam und wahrscheinlich eine gute Angewohnheit.
Damen TheSifter
2
Mich interessiert, warum alle Beispiele "undefiniert" als zusätzliches Argument in der Funktion verwenden? Es kann jedoch vorkommen, dass jemand versehentlich einen zusätzlichen (definierten) Parameter übergibt und die gesamte Logik fehlschlägt. Warum nicht so etwas wie function () {var _undef; if (someVal == _undef) {etwas tun}};
Oleksandr_DJ
4
@Oleksandr_DJ Genau. Bilden Sie einen Wert, von dem Sie wissenundefined , dass er ist, und weisen Sie ihn undefinedim Umfang zu. Lassen undefinedSie das Schreiben nicht offen, wenn Sie "zu viele" Argumente eingeben. Das führt zu Fehlern und ist von Natur aus nicht defensiv, insbesondere wenn es, wie Lucero betont , sehr einfache Alternativen gibt, um solide undefinedWerte in den Geltungsbereich zu bringen.
Ruffin
19

Dafür gibt es eine einfache Lösung: Vergleichen, gegen void 0die immer undefiniert ist.

Beachten Sie, dass Sie dies vermeiden sollten, ==da dies die Werte erzwingen kann. Verwenden Sie stattdessen ===(und !==).

Das heißt, die undefinierte Variable kann irrtümlich gesetzt werden, wenn jemand schreibt, =anstatt ==etwas mit etwas zu vergleichen undefined.

Lucero
quelle
IMO, das ist die beste Antwort.
Abhisekp
1
Bedenken Sie, dass dies foo === void 0möglicherweise nicht so foo === undefinedflüssig undefinedist und dass unveränderliche Daten von modernen Browsern (IE 9+) vollständig unterstützt werden, wie Sie in dieser Kompatibilitätstabelle sehen können.
Daniel AR Werner
3

Nur Sie wissen, welchen Code Sie verwenden und wie gefährlich er ist. Diese Frage kann nicht so beantwortet werden, wie Sie es geklärt haben.

1) Erstellen Sie eine Teamrichtlinie, lassen Sie die Neudefinition von undefiniert nicht zu und reservieren Sie sie für die häufigere Verwendung. Scannen Sie Ihren vorhandenen Code nach undefinierter linker Zuordnung.

2) Wenn Sie nicht alle Szenarien kontrollieren, wenn Ihr Code außerhalb von Situationen verwendet wird, die Sie oder Ihre Richtlinien kontrollieren, ist Ihre Antwort offensichtlich anders. Scannen Sie den Code, der Ihre Skripte verwendet. Wenn Sie möchten, durchsuchen Sie das Web nach Statistiken über undefinierte Linkszuweisungen, aber ich bezweifle, dass dies für Sie getan wurde, da es einfacher ist, stattdessen nur Antwort 1 oder 3 hier zu verfolgen.

3) Und wenn diese Antwort nicht gut genug ist, liegt es wahrscheinlich daran, dass Sie wiederum eine andere Antwort benötigen. Möglicherweise schreiben Sie eine beliebte Bibliothek, die in Unternehmensfirewalls verwendet wird, und Sie haben keinen Zugriff auf den aufrufenden Code. Verwenden Sie dann eine der anderen guten Antworten hier. Beachten Sie, dass die beliebte jQuery-Bibliothek die Soundkapselung praktiziert und beginnt:

(function( window, undefined ) {

Nur Sie können Ihre Frage auf die von Ihnen gewünschte Weise beantworten. Was gibt es noch zu sagen?

edit: ps wenn du wirklich meine meinung willst, sage ich dir, dass es überhaupt nicht gefährlich ist. Alles, was so wahrscheinlich zu Fehlern führen würde (z. B. die Zuordnung zu undefiniert, was offensichtlich ein gut dokumentiertes Risikoverhalten ist), ist selbst ein Fehler. Es ist der Defekt, der das Risiko darstellt. Aber das ist nur in meinen Szenarien, in denen ich es mir leisten kann, diese Perspektive beizubehalten. Wie ich Ihnen empfehlen würde, habe ich die Frage für meine Anwendungsfälle beantwortet.

Shannon
quelle
3

Es ist sicher, gegen undefinierte zu testen. Wie Sie bereits erwähnen. Wenn Sie zu einem Code gelangen, der ihn überschreibt (was sehr verbesserungsfähig ist), verwenden Sie ihn einfach nicht mehr.

Wenn Sie eine Bibliothek für den öffentlichen Gebrauch erstellen, können Sie möglicherweise einige der Techniken verwenden, um zu vermeiden, dass der Benutzer sie ändert. Aber selbst in diesem Fall ist es ihr Problem, nicht Ihre Bibliothek.

Bart Calixto
quelle
2

Sie können undefinedin Ihrem Code Codierungen für Browser verwenden, die ECMAScript 5.1 unterstützen, da diese gemäß der Sprachspezifikation unveränderlich sind .

Siehe auch diese Kompatibilitätstabelle oder diese caniuse ECMAScript 5 zu sehen , dass alle modernen Browser (IE 9+) unveränderlich umgesetzt habenundefined .

Daniel AR Werner
quelle
1

Es ist überhaupt nicht gefährlich. Es kann nur überschrieben werden, wenn es mit einem ES3-Motor betrieben wird, und das wird wahrscheinlich nicht mehr verwendet.

kirk.burleson
quelle
0

Erstens, wenn Ihr Code kaputt geht, liegt das wahrscheinlich nicht daran, dass ein anderer Entwickler da draußen "versucht, ein Idiot zu sein", wie Sie es ausdrücken.

Es ist wahr, dass dies undefinedkein Schlüsselwort ist. Aber es ist ein Primitiv auf globaler Ebene. Es sollte so verwendet werden (siehe "undefiniert" unter developer.mozilla.org ):

var x;
if (x === undefined) {
    // these statements execute
}
else {
    // these statements do not execute
}

Die übliche Alternative dazu (auch von MDN ) und meiner Meinung nach der bessere Weg ist:

// x has not been declared before
if (typeof x === 'undefined') { // evaluates to true without errors
    // these statements execute
}

if(x === undefined){ // throws a ReferenceError

}

Was einige Vorteile hat, ist der offensichtliche (aus den Kommentaren), dass es keine Ausnahme auslöst, wenn x nicht deklariert ist. Es ist auch erwähnenswert, dass MDN weist darauf hin, dass es wichtig ist , zu verwenden , ===über ==im ersten Fall , weil:

var x=null;
if (x === undefined) {
    // this is probably what you meant to do
    // these lines will not execute in this case
}
else if (x == undefined) {
    // these statements will execute even though x *is* defined (as null)
}
else {
    // these statements do not execute
}

Dies ist ein weiterer oft übersehener Grund, warum es wahrscheinlich in allen Fällen besser ist, nur die zweite Alternative zu verwenden.

Fazit: Es ist nicht falsch, es auf die erste Weise zu codieren, und schon gar nicht gefährlich. Das Argument, das Sie als Beispiel dafür gesehen haben (das überschrieben werden kann), ist nicht das stärkste Argument für die Codierung der Alternative mit typeof. Die Verwendung typeofist jedoch aus einem bestimmten Grund stärker: Sie löst keine Ausnahme aus, wenn Ihre Variable nicht deklariert ist. Es könnte auch argumentiert werden, dass die Verwendung von ==anstelle von ===ein häufiger Fehler ist. In diesem Fall wird nicht das getan, was Sie erwartet haben. Warum also nicht verwenden typeof?

Tintenfisch
quelle
1
"Was einige Vorteile hat, ist offensichtlich, dass es keine Ausnahme auslöst, wenn x nicht deklariert ist." Lass mich das klarstellen. Sie halten es für einen Vorteil , die Ausnahme, die bei Verwendung einer nicht deklarierten Variablen auftritt, stillschweigend zu ignorieren? Das scheint sehr fehleranfällig zu sein. Können Sie erklären, warum Sie denken, dass dies kein schrecklicher Nachteil ist?
Cosmologicon