Welchen Grund gibt es, in JavaScript null anstelle von undefiniert zu verwenden?

103

Ich schreibe schon ziemlich lange JavaScript und hatte nie einen Grund, es zu verwenden null. Es scheint, dass dies undefinedimmer vorzuziehen ist und programmgesteuert denselben Zweck erfüllt. Was sind einige praktische Gründe, nullanstatt zu verwenden undefined?

Jimmy Cuadra
quelle
Dies ist ein mögliches Duplikat von stackoverflow.com/questions/461966/…
salmonsea
Nun, es gibt Methoden wie diese document.getElementById(), die zurückkehren können, nullaber nicht. undefinedWarum sollten Sie in diesen Fällen die Rückgabe testen undefined? (Sicher, es würde funktionieren , wenn Sie verwenden , ==anstatt ===, aber immer noch, warum sollten Sie sich bewusst Test für die falsche Sache?)
nnnnnn
Es kann hilfreich sein, vorhersehbare Typen zu haben, und dies kann das Denken bei der Verwendung des einen oder anderen leiten. Wenn ein Objekt immer zurückgegeben wird, vom Design benötigt oder gewünscht wird, verwenden Sie null für falsche Ergebnisse (z document.getElementById('does-not-exist'). B. ). Variablen var a;und Funktionsrückgabewerte sind standardmäßig undefiniert. In der Vergangenheit befand sich null im globalen Bereich, daher verlangsamte die Verwendung die Ausführung und führte dazu, dass ich andere falsche Typen (false, '', 0) freien Referenzen vorzog. Ich persönlich vermeide Null, es sei denn, es gibt einen zwingenden Grund, weil ich es als einfacher empfinde, was im Allgemeinen besser ist.
Jimmy

Antworten:

59

Null und undefiniert sind im Wesentlichen zwei verschiedene Werte, die dasselbe bedeuten. Der einzige Unterschied besteht in den Konventionen, wie Sie sie in Ihrem System verwenden. Wie einige erwähnt haben, verwenden einige Leute null, um "kein Objekt" zu bedeuten, wobei Sie manchmal ein Objekt erhalten, während undefiniert bedeutet, dass kein Objekt erwartet wurde (oder dass ein Fehler aufgetreten ist). Mein Problem dabei ist, dass es völlig willkürlich und völlig unnötig ist.

Es gibt jedoch einen großen Unterschied: Variablen, die nicht initialisiert wurden (einschließlich Funktionsparametern, bei denen unter anderem kein Argument übergeben wurde), sind immer undefiniert.

Aus diesem Grund verwende ich in meinem Code niemals null, es sei denn, etwas, das ich nicht kontrolliere, gibt null zurück (z. B. Regex-Matching). Das Schöne daran ist, dass es die Dinge sehr vereinfacht. Ich muss nie überprüfen, ob x === undefined || x === null. Und wenn Sie die Gewohnheit haben, == zu verwenden oder einfach Dinge wie if (x) .... Hör auf. !xwird für eine leere Zeichenfolge, 0, null, NaN als wahr ausgewertet - dh Dinge, die Sie wahrscheinlich nicht wollen. Wenn Sie Javascript schreiben möchten, das nicht schrecklich ist, verwenden Sie immer Triple Equals === und niemals Null (verwenden Sie stattdessen undefined). Es wird dir das Leben leichter machen.

BT
quelle
135
Ich bin damit nicht einverstanden. Null wird verwendet, um etwas programmgesteuert Leeres zu definieren. Undefiniert bedeutet, dass die Referenz nicht vorhanden ist. Ein Nullwert hat einen definierten Verweis auf "nichts". Wenn Sie eine nicht vorhandene Eigenschaft eines Objekts aufrufen, werden Sie undefiniert. Wenn ich diese Eigenschaft absichtlich leer machen würde, muss sie null sein, damit Sie wissen, dass sie absichtlich ist. Viele Javascript-Bibliotheken funktionieren auf diese Weise.
com2ghz
6
@ com2ghz Was Sie beschreiben, ist eine von vielen Philosophien. Viele js-Bibliotheken funktionieren tatsächlich so. Viele arbeiten auch nicht so. In Javascript können Sie einen expliziten undefinierten Wert genauso einfach in einem Objekt oder Array speichern wie mit null. Die Bedeutungen von beiden sind vollständig und vollständig kontextabhängig. IE sie bedeuten, was Sie wollen, dass sie bedeuten.
BT
3
Deshalb ist JS eine schreckliche Sprache. Wie Sie sagen, haben viele Bibliotheken ihre eigenen Philosophien, aber Sie schließen viele Bibliotheken für ein Projekt ein. Sie stoßen also auf viele Konventionen dieser Bibliotheken. Wie oft müssen Sie verschiedene Fälschungsprüfungen durchführen? Es wäre nicht das letzte Mal, dass Sie ein Nullobjekt mit einer Zeichenfolge verknüpfen und eine "Null" als Zeichenfolge erhalten. Oder Sie übergeben eine 0 als numerischen Wert und fragen sich, warum die IF-Anweisung t als falsch behandelt.
com2ghz
2
@ com2ghz Also ist JS eine schreckliche Sprache, weil sie sowohl null als auch undefiniert ist? Ich kann Dutzende von schlechten Sprachentscheidungen in allen wichtigen Sprachen zählen, js ist keine Ausnahme. Ich muss oder möchte buchstäblich nie falsche Überprüfungen in meinem Code verwenden und verwende immer ===oder !==. JS ist eine fantastisch ausdrucksstarke Sprache, wenn Sie wissen, wie man sie benutzt.
BT
6
Richtig. Ich habe gerade erfahren, dass die null/ undefined-Dichotomie notwendig ist, weil die ursprüngliche Version von JS nicht hatte hasOwnPropertyoder der inOperator. Jetzt verstehe ich nicht wirklich, warum einer von ihnen in ES6 oder anderen ES7-Vorschlägen, die ich gesehen habe, nicht abgeschafft wurde.
Andy
86

Ich habe keine wirkliche Antwort, aber laut Nicholas C. Zakas , Seite 30 seines Buches " Professionelles JavaScript für Webentwickler " :

Wenn Sie eine Variable definieren, die später ein Objekt enthalten soll, ist es ratsam, die Variable nullim Gegensatz zu anderen Elementen zu initialisieren . Auf diese Weise können Sie explizit nach dem Wert suchen, nullum festzustellen, ob die Variable zu einem späteren Zeitpunkt mit einer Objektreferenz gefüllt wurde

bbg
quelle
8
+1 Ja, ich stimme zu und ich versuche immer daran zu denken, vars auf null zu initialisieren. Dann bin ich mir (ziemlich) sicher, undefineddass eine Katastrophe passiert ist. Nur imho.
Pete Wilson
9
@Pete - aber es sagt dir nichts über die "Katastrophe", also was ist der Sinn? Und Sie können diese Annahme nur treffen, wenn Sie wissen, dass die Funktion der Konvention entspricht.
RobG
7
Andererseits können Sie die Variable auch mit initialisieren var myVar;und explizit nach dem Wert suchen, undefinedum festzustellen, ob er zu einem späteren Zeitpunkt mit einer Objektreferenz gefüllt wurde. Mein Punkt ist, dass dies völlig akademisch ist - Sie können es so oder so tun, und jeder, der einen Weg über den anderen rät, drängt einfach auf seine eigene Konvention.
Dooan
1
Das einzige Problem, das ich habe (seit ich vor 15 Jahren mit JavaScript angefangen habe), ist, dass Sie zu oft testen müssen undefinedund null. Das ist immer noch sehr nervig. Ich vermeide es, eine Variable nullzuzuweisen, um die Anzahl der zusätzlichen nullTests zu verringern .
G Man
4
@GMan - Dies ist der einzige Ort, an dem der ==Vergleich (im Gegensatz zu ===) sinnvoll ist: v == null(oder v == undefined) prüft auf null oder undefiniert.
Rick Love
14

Am Ende des Tages können Sie beide technisch verwenden, um die Arbeit zu erledigen , da beide nullund undefinedderselbe Wert ( Boolean(undefined) === false && Boolean(null) === false) erzwungen werden. Es gibt jedoch den richtigen Weg, IMO.

  1. Überlassen Sie die Verwendung undefineddem JavaScript-Compiler.

    undefinedwird verwendet, um Variablen zu beschreiben, die nicht auf eine Referenz verweisen. Es ist etwas, das der JS-Compiler für Sie erledigt. Zur Kompilierungszeit setzt die JS-Engine den Wert aller angehobenen Variablen auf undefined. Sobald der Motor den Code durchläuft und Werte verfügbar werden, weist der Motor den jeweiligen Variablen entsprechende Werte zu. Für diejenigen Variablen, für die keine Werte gefunden wurden, behalten die Variablen weiterhin einen Verweis auf das Grundelement bei undefined.

  2. Verwenden Sie null nur, wenn Sie den Wert einer Variablen explizit als "kein Wert" bezeichnen möchten.

    Wie @ com2gz angibt: nullwird verwendet, um etwas programmgesteuert Leeres zu definieren. undefinedsoll sagen, dass die Referenz nicht existiert. Ein nullWert hat einen definierten Verweis auf "nichts". Wenn Sie eine nicht vorhandene Eigenschaft eines Objekts aufrufen, erhalten Sie undefined. Wenn ich diese Eigenschaft absichtlich leer machen würde, dann muss es nullso sein, dass Sie wissen, dass es absichtlich ist.

TLDR; Verwenden Sie nicht das undefinedGrundelement. Dies ist ein Wert, den der JS-Compiler automatisch für Sie festlegt, wenn Sie Variablen ohne Zuweisung deklarieren oder wenn Sie versuchen, auf Eigenschaften von Objekten zuzugreifen, für die es keine Referenz gibt. Verwenden nullSie diese Option nur dann, wenn Sie absichtlich möchten, dass eine Variable "keinen Wert" hat.

Ich habe nie explizit etwas auf undefiniert gesetzt (und ich bin in den vielen Codebasen, mit denen ich interagiert habe, nicht darauf gestoßen). Auch benutze ich selten null. Ich verwende nullnur dann, wenn ich den Wert eines Arguments für eine Funktion als wertlos bezeichnen möchte, dh:

function printArguments(a,b) {
  console.log(a,b);
}

printArguments(null, " hello") // logs: null hello
Govind Rai
quelle
Dies sollte die ausgewählte Antwort gewesen sein
Alaboudi
13

undefiniert ist, wo keine Vorstellung von der Sache existiert; Es hat keinen Typ und wurde in diesem Bereich noch nie referenziert. Bei null ist bekannt, dass das Ding existiert, aber es hat keinen Wert.

Yaplex
quelle
4
Woher wissen Sie, ob versucht wurde, einen Wert zuzuweisen, der jedoch fehlgeschlagen ist und stattdessen undefiniert zugewiesen wurde?
RobG
11

Jeder hat seine eigene Codierungsmethode und seine eigene interne Semantik, aber im Laufe der Jahre habe ich festgestellt, dass dies der intuitivste Rat ist, den ich Leuten gebe, die diese Frage stellen: Wenn Sie Zweifel haben, tun Sie, was JavaScript tut .

Angenommen, Sie arbeiten mit Objekteigenschaften wie Optionen für ein jQuery-Plugin. Fragen Sie sich, welchen Wert JavaScript für eine Eigenschaft hat, die noch definiert werden muss. Die Antwort lautet undefined. In diesem Zusammenhang würde ich diese Art von Dingen mit 'undefined' initialisieren, um mit JavaScript konsistent zu sein (für Variablen können Sie dies var myVar;anstelle von tun var myVar = undefined;).

Angenommen, Sie führen eine DOM-Manipulation durch. Welchen Wert weist JavaScript nicht vorhandenen Elementen zu? Die Antwort lautet null. Dies ist der Wert, mit dem ich initialisieren würde, wenn Sie eine Platzhaltervariable erstellen, die später einen Verweis auf ein Element, ein Dokumentfragment oder ähnliches enthält, das sich auf das DOM bezieht.

Wenn Sie mit JSON arbeiten, muss ein Sonderfall erstellt werden: Für undefinierte Eigenschaftswerte sollten Sie diese entweder festlegen ""oder nullweil ein Wert von undefinednicht als geeignetes JSON-Format angesehen wird.

Wenn Sie feststellen, dass Sie Dinge mit nulloder undefinedmehr als einmal in einem blauen Mond initialisieren , sollten Sie vielleicht überlegen, wie Sie Ihre App codieren.

thdoan
quelle
Obwohl dies eine gute Haltung ist, möchte ich diese Antwort hinzufügen: stackoverflow.com/a/37980662/883303
Frederik Krautwald
@FrederikKrautwald danke für den Link - das ist eine sehr klare Abgrenzung.
Donnerstag,
10

Sie könnten die hier vorgeschlagene Konvention übernehmen, aber es gibt wirklich keinen guten Grund dafür. Es wird nicht konsequent genug verwendet, um sinnvoll zu sein.

Um die Konvention nützlich zu machen, müssen Sie zunächst wissen, dass die aufgerufene Funktion der Konvention folgt. Dann müssen Sie den zurückgegebenen Wert explizit testen und entscheiden, was zu tun ist. Wenn Sie undefiniert werden , können Sie davon ausgehen, dass ein Fehler aufgetreten ist , von dem die aufgerufene Funktion wusste . Aber wenn ein Fehler aufgetreten ist und die Funktion davon wusste und es nützlich ist, diesen an die weitere Umgebung zu senden, warum nicht ein Fehlerobjekt verwenden? dh einen Fehler werfen?

Letztendlich ist die Konvention in nichts anderem als in sehr kleinen Programmen in einfachen Umgebungen praktisch nutzlos.

RobG
quelle
3

Eine nützliche Eigenschaft in null , die nicht definiert ist, ist nicht qualifiziert:

> null + 3
3
> undefined + 3
NaN

Ich verwende, nullwenn ich einen numerischen Wert "ausschalten" oder einen initialisieren möchte. Meine letzte Verwendung war die Manipulation der CSS-Transformation:

const transforms = { perspective : null, rotateX : null };
// if already set, increase, if not, set to x
runTimeFunction((x) => { trasforms.perspective += x; });
// still useful, as setting perspective to 0 is different than turning it off
runTimeFunction2((x) => { transforms.perspective = null; });

// toCss will check for 'null' values and not set then at all
runTimeFunction3(() => { el.style.transform = toCss(transforms); });

Nicht sicher , ob ich sollte diese Eigenschaft Gedanken verwenden ...

Faccion
quelle
2

DOM-Knoten und -Elemente sind nicht undefiniert, können jedoch null sein.

  • Das nextSibling des letzten untergeordneten Elements eines Elements ist null.

  • Das vorherige Geschwister des ersten Kindes ist null.

  • Eine document.getElementById-Referenz ist null, wenn das Element im Dokument nicht vorhanden ist.

In keinem dieser Fälle ist der Wert jedoch undefiniert . Es gibt dort einfach keinen Knoten.

kennebec
quelle
Danke für die Erklärung. Für mich könnte dies nicht kontraintuitiver sein.
Tomékwi
Es hängt wirklich davon ab, was Sie überprüfen möchten. Wenn Sie beispielsweise sehen möchten, ob eine globale Variable mit dem Namen "myVar" vorhanden ist, wird "undefined" window.myVarzurückgegeben, wenn sie nicht vorhanden ist. Es gibt Unmengen von Dingen, die in JavaScript "undefiniert" zurückgeben, nur Unmengen von Dingen, die "null" zurückgeben - alles hängt vom Kontext ab.
Dooan
2

Einige haben gesagt, dass es in Ordnung ist, Objekte zu initialisieren null. Ich wollte nur darauf hinweisen, dass die Standardeinstellungen für destrukturierende Argumente nicht funktionieren null. Beispielsweise:

const test = ({ name } = {}) => {
  console.log(name)
}

test() // logs undefined
test(null) // throws error

Dies erfordert die Durchführung von nullÜberprüfungen vor dem Aufruf der Funktion, was häufig vorkommen kann.

Matt Way
quelle
1

Ich arbeite gerade an dieser genauen Frage und betrachte die folgende Philosophie:

  1. Jede Funktion, die ein Ergebnis zurückgeben soll, sollte null zurückgeben, wenn sie kein Ergebnis findet
  2. Jede Funktion, die NICHT dazu bestimmt ist, ein Ergebnis zurückzugeben, gibt implizit undefiniert zurück.

Für mich ist diese Frage von Bedeutung, da jeder, der eine Funktion aufruft, die ein Ergebnis zurückgibt, keine Frage haben sollte, ob er auf undefiniert gegen null testen soll.

Diese Antwort versucht nicht zu adressieren:

  1. Eigenschaftswerte von null gegen undefiniert
  2. Variablen in Ihren Funktionen sind null oder undefiniert

Meiner Meinung nach sind Variablen Ihr eigenes Geschäft und kein Teil Ihrer API, und Eigenschaften in jedem OO-System sind definiert und sollten daher mit einem anderen Wert definiert werden, als wenn sie nicht definiert wären (null für definiert, undefiniert ist das, was Sie sind erhalten, wenn Sie auf etwas zugreifen, das sich nicht in Ihrem Objekt befindet).

Michael
quelle
1

Hier ist ein Grund: var undefined = 1 Ist legal Javascript, ist aber var null = 1ein Syntaxfehler. Der Unterschied besteht darin, dass nulles sich um ein Sprachschlüsselwort undefinedhandelt, aus irgendeinem Grund jedoch nicht.

Wenn sich Ihr Code auf Vergleiche stützt, undefinedals ob es sich um ein Schlüsselwort handelt ( if (foo == undefined)ein sehr einfacher Fehler), das nur funktioniert, weil niemand eine Variable mit diesem Namen definiert hat. Der gesamte Code ist anfällig für Personen, die versehentlich oder böswillig eine globale Variable mit diesem Namen definieren. Natürlich wissen wir alle, dass es in Javascript völlig unmöglich ist, versehentlich eine globale Variable zu definieren ...

Joel Mueller
quelle
1
Verwenden Sie void 0anstelle von undefiniert.
Frederik Krautwald
1

Ich möchte nur hinzufügen, dass bei Verwendung bestimmter Javascript-Bibliotheken null und undefiniert unbeabsichtigte Konsequenzen haben können.

Zum Beispiel die getFunktion von lodash , die einen Standardwert als drittes Argument akzeptiert:

const user = {
  address: {
    block: null,
    unit: undefined,
  }
}
console.log(_.get(user, 'address.block', 'Default Value')) // prints null
console.log(_.get(user, 'address.unit', 'Default Value')) // prints 'Default Value'
console.log(_.get(user, 'address.postalCode', 'Default Value')) // prints 'Default Value'

Ein weiteres Beispiel: Wenn Sie defaultProps in React verwenden und eine Eigenschaft übergeben wird null, werden Standard-Requisiten nicht verwendet, da null als definierter Wert interpretiert wird . z.B

class MyComponent extends React.Component {
   static defaultProps = {
      callback: () => {console.log('COMPONENT MOUNTED')},
   }
   componentDidMount() {
      this.props.callback();
   }
}
//in some other component
<MyComponent />   // Console WILL print "COMPONENT MOUNTED"
<MyComponent callback={null}/>   // Console will NOT print "COMPONENT MOUNTED"
<MyComponent callback={undefined}/>   // Console WILL print "COMPONENT MOUNTED"
lilbitofchee
quelle
0

Ich bin völlig anderer Meinung, dass eine Verwendung von null oder undefiniert nicht erforderlich ist. undefiniert ist etwas, das den gesamten Verkettungsprozess des Prototyps am Leben erhält. Daher kann der Compiler nur mit null nicht überprüfen, ob diese Eigenschaft nur null ist oder nicht im Endpunktprototyp definiert ist. In anderen dynamischen typisierten Sprachen (z. B. Python) wird eine Ausnahme ausgelöst, wenn Sie auf nicht definierte Eigenschaften zugreifen möchten. Bei prototypbasierten Sprachen sollte der Compiler jedoch auch übergeordnete Prototypen überprüfen. Hier ist der Ort, an dem undefinierte Sprachen am meisten benötigt werden.

Die ganze Bedeutung der Verwendung von Null besteht darin, nur eine Variable oder Eigenschaft an ein Objekt zu binden, das Singleton ist und die Bedeutung der Leere hat, und auch die Verwendung von Null hat Leistungszwecke. Diese 2 Codes haben unterschiedliche Ausführungszeiten.

var p1 = function(){this.value = 1};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p1();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p;
});
big_array.reduce((sum, p)=> sum + p.value, 0)

var p2 = function(){this.value = 1, p.x = null};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p2();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p; 
});
big_array.reduce((sum, p)=> sum + p.value, 0)
VahagnNikoghosian
quelle