typeof! == „undefined” vs.! = null

491

Często widzę kod JavaScript, który sprawdza niezdefiniowane parametry w ten sposób:

if (typeof input !== "undefined") {
    // do stuff
}

Wydaje się to trochę marnotrawstwem, ponieważ obejmuje zarówno wyszukiwanie typu, jak i porównywanie ciągów, nie mówiąc już o szczegółowości. Jest to potrzebne, ponieważ undefinedmożna go zmienić.

Moje pytanie brzmi: w
jaki sposób ten kod jest lepszy od tego podejścia:

if (null != input) {
    // do stuff
}

O ile mi wiadomo, nie można na nowo zdefiniować null, więc nie pęknie niespodziewanie. Z powodu przymusu !=operatora operator sprawdza to zarówno undefinedi null... co często jest dokładnie tym, czego chcesz (np. Opcjonalnymi parametrami funkcji).

Jednak ta forma nie wydaje się powszechna, a nawet powoduje, że JSLint krzyczy na ciebie za użycie złego !=operatora.

Dlaczego jest to uważane za zły styl?

Derek Thurn
źródło
13
@ Marcel, nie ma prawdziwej różnicy, ale istnieją dwa powody, aby to zrobić. Po pierwsze, dla niektórych czytelniej jest czytać. Drugim powodem jest to, że zapobiega przypadkowemu nadpisaniu zmiennej. Czy kiedykolwiek to zrobiłeś: if (foo = „wartość”), gdy zamierzasz dokonać porównania. Jeśli nauczysz się nawracać zmienną w operatorze przypisania / porównania, nie będziesz miał tego problemu.
Layke,
29
Dla niektórych (w tym dla mnie) jest to trudniejsze do odczytania. Ponadto większość IDE ostrzega przed przypadkowym przydzieleniem. Ale nadal używam tego formularza, jeśli porównywana zmienna jest bardzo długa. YMMV.
johndodo
15
@MarcelKorpel To się nazywa „warunek Yoda”: umumble.com/blogs/Programming/321
kol.
55
Jest trudniejszy do odczytania. Nie mówi się: „Butelka nie jest pusta”.
Noel Abrahams
11
if (null != input)to tylko „Yoda Speak” dla anglojęzycznego (jednego z nich jestem… uuammmmm), więc jeśli równa się to samo, to tak naprawdę jest to tylko semantyka. MOIM ZDANIEM.
webLacky3rdClass

Odpowiedzi:

709

typeof jest bezpieczniejszy, ponieważ pozwala nigdy nie zadeklarować identyfikatora wcześniej:

if(typeof neverDeclared === "undefined") // no errors

if(neverDeclared === null) // throws ReferenceError: neverDeclared is not defined
seanmonstar
źródło
3
if ((typeof neverDeclared! == "undefined") && (neverDeclared! == null)) {return true; } else {return false; }
Anthony DiSanti
88
Użyj === podczas porównywania z null / undefined.
MyGGaN
47
@MyGGaN tylko wtedy, gdy chcesz je rozróżnić. W wielu przypadkach ==może być lepiej, ponieważ sprawdza zarówno wartość zerową, jak i niezdefiniowaną.
seanmonstar
10
Nie mogę znaleźć żadnej różnicy między typeof somevar == „undefined” a typeof somevar === „undefined”, ponieważ typeof zawsze zwraca ciąg znaków. Dla null zwróci „obiekt”. A może dlatego, że się mylę?
TomTom
2
Uważam, że komentarz @ TomTom stanowi sedno problemu - nie rozumiem, dlaczego ktoś używałby operatorów !==lub ===podczas porównywania wartości, której typem jest ciąg znaków.
Nicolas Rinaudo,
49

Jeśli zmienna jest zadeklarowana (za pomocą varsłowa kluczowego, jako argument funkcji lub jako zmienna globalna), myślę, że najlepszym sposobem na to jest:

if (my_variable === undefined)

jQuery to robi, więc jest dla mnie wystarczająco dobry :-)

W przeciwnym razie będziesz musiał użyć, typeofaby uniknąć ReferenceError.

Jeśli spodziewasz się, że niezdefiniowane zostanie ponownie zdefiniowane, możesz owinąć swój kod w następujący sposób:

(function(undefined){
    // undefined is now what it's supposed to be
})();

Lub uzyskaj go za pośrednictwem voidoperatora:

const undefined = void 0;
// also safe
Joey Adams
źródło
1
Jeśli niezdefiniowany został już zdefiniowany, to czy nie przekazałbyś go do swojej anonimowej funkcji przez parametr o nazwie niezdefiniowany, nie osiągając niczego?
Anthony DiSanti
20
@Anthony DiSanti: Nie, undefinedto nazwa nadana parametrowi funkcji, a nie jego wartość. Nic nie jest przekazywane do funkcji, co oznacza, że ​​wartość pierwszego parametru jest niezdefiniowana.
Joey Adams
3
Ach mój błąd, dziękuję za kontynuację. Przepuściłem głos, przepraszam za to.
Anthony DiSanti
2
Po co pisać wyjątek do obsługi niezdefiniowanego zadeklarowania przez innego programistę, skoro można to zrobić poprawnie na początek? jQuery otacza początkową anonimową funkcję wyświetlaną w funkcji, aby upewnić się, że niezdefiniowana nie została zdefiniowana, i aby zmniejszyć zminimalizowany rozmiar. Mówiąc najprościej, jeśli może dać nieoczekiwane wyniki, aby zrobić to w ten sposób, po co ryzykować leniwe programowanie, aby uniknąć wpisywania się (typeof zmienna === „undefined”). Co jeśli chcielibyśmy (typeof zmienna === „obiekt”), czy powinniśmy podać zmienną domyślną, która jest również obiektem, abyśmy mogli to zrobić (zmienna === obiekt)?
fyrye
28

dobry sposób:

if(typeof neverDeclared == "undefined") //no errors

Ale najlepiej wyglądającym sposobem jest sprawdzenie za pomocą:

if(typeof neverDeclared === typeof undefined) //also no errors and no strings
Żart
źródło
6
var undefined = function () {}; if (typeof neverDeclared === typeof undefined); neverDecalred! = 'function'; jsfiddle.net/hbPZ5 zwracany typ var; zwraca ciąg. Brak błędów lub ciągów, ale nie zawsze da oczekiwane wyniki. Przyznani programiści nie powinni deklarować niezdefiniowanych, ale istnieją pewne frameworki i biblioteki, które to robią.
fyrye
1
Używam głównie, if (typeof neverDeclared === typeof undefined) { ale Lint zgłasza błąd. „Spodziewałem się ciągu i zamiast tego zobaczyłem„ typeof ”.” Jak obejdziesz ten błąd? Czy powinniśmy podporządkować się żądaniom Linta i zamiast tego skorzystać z „dobrej drogi”?
Ayelis,
2
@fyrye Czy znasz jakieś biblioteki / struktury JavaScript, które faktycznie mutują niezdefiniowane? Wiem, że to możliwe; ale chciałbym znaleźć dziki przykład: „Tutaj możesz spotkać tego paskudnego gnu!”
bigtunacan
4
typeof neverDeclared === typeof void 0;-D
Alex Yaroshevich
1
Jest podatny na błędy, ponieważ w rzeczywistości polegasz na tym, że pewna zmienna („niezdefiniowana”) nie jest zdefiniowana. Co może być fałszywe, jak pokazały inne posty. Zawsze możesz to zrobić, if(typeof neverDeclared === typeof undefined_variable_with_a_name_assumed_to_be_never_defined) {ale jest to dość długie.
Pierre-Olivier Vares,
12

Naprawdę nie powinieneś się martwić, że nazwa niezdefiniowana zostanie zmieniona. Jeśli ktoś zmieni niezdefiniowaną nazwę, będziesz miał o wiele więcej kłopotów niż tylko kilka, jeśli kontrole się nie powiodą. Jeśli naprawdę chcesz chronić swój kod, umieść go w IFFE (natychmiast wywołane wyrażenie funkcji) w następujący sposób:

(function($, Backbone, _, undefined) {
    //undefined is undefined here.
})(jQuery, Backbone, _);

Jeśli pracujesz ze zmiennymi globalnymi (co już jest niepoprawne) w środowisku przeglądarki, sprawdziłbym, czy nie są zdefiniowane w ten sposób:

if(window.neverDefined === undefined) {
    //Code works
}

Ponieważ zmienne globalne są częścią obiektu okna, możesz po prostu sprawdzić przed niezdefiniowanym zamiast rzutować na ciąg i porównywać ciągi.

Ponadto, dlaczego twoje zmienne nie są zdefiniowane? Widziałem dużo kodu, w którym sprawdzają istnienie zmiennych i wykonują na tej podstawie pewne działania. Ani razu nie widziałem, gdzie to podejście było prawidłowe.

Peeter
źródło
1
Sprawdzanie poprawności danych wejściowych i sprawdzanie zależności są dobrym powodem do tego. Jeśli mam pliki JavaScript, które są zależne od innych załadowanych plików lub zadeklarowanych obiektów inicjujących, przydatne jest przetestowanie obiektów lub właściwości pliku zależnych od niezdefiniowanego i wygenerowanie miłego wyjątku zamiast pozwalania skryptowi zawieść w nieprzewidywalny sposób.
AmericanUmlaut
Wygląda na to, że możesz potrzebować czegoś z linii AMD (wymagany.js)
Peeter
1
A może po prostu chcę zrobić bardzo proste porównanie, zamiast włączać inną bibliotekę do mojego projektu :)
AmericanUmlaut
Za późno na edycję :(. Chciałem dodać - wymaga.js również nie jest odpowiednim rozwiązaniem do sprawdzania poprawności danych wejściowych (obiekty init, o których wspomniałem w moim początkowym komentarzu). Jeśli masz obiekt, który ma być wypełniony pewnymi wartości przed załadowaniem skryptu, warto zgłosić wyjątek, jeśli nie są one zdefiniowane
AmericanUmlaut
1
Nie, ponieważ typeof zwraca ciąg znaków. Zatem typeof undefined zwraca „undefined”. window.input! == undefined (jeśli twoja zmienna znajduje się w globalnym spoce)
Peeter
5

Jeśli naprawdę martwisz się przedefiniowaniem niezdefiniowanego, możesz zabezpieczyć się przed tym za pomocą metody pomocniczej, takiej jak ta:

function is_undefined(value) {
   var undefined_check; // instantiate a new variable which gets initialized to the real undefined value
   return value === undefined_check;
}

To działa, ponieważ kiedy ktoś pisze undefined = "foo"tylko on pozwala na imię undefined odniesienie do nowej wartości, ale nie zmienia się wartość rzeczywistą undefined.

Ivo Wetzel
źródło
1
Wprowadzono jednak wywołanie funkcji, które obniży wydajność.
Tim Down
Nie sądzę, że to wywołanie funkcji zabije wydajność, jest znacznie bardziej prawdopodobne, że DOM będzie wąskim gardłem. Ale w każdym razie, jeśli masz swoją zwykłą dużą anonimową funkcję, która zawiera dowolną bibliotekę, możesz również zdefiniować undefined_checkna górze, a następnie po prostu użyć jej wszędzie w kodzie.
Ivo Wetzel,
1
Zgadzam się i nie twierdzę, że to zły pomysł. Warto tylko zaznaczyć, że wywołanie tej funkcji będzie działało wolniej niż typeofsprawdzanie.
Tim Down
Myślę, że ta funkcja jest na tyle prosta, że ​​będzie wbudowana, więc nie wpłynie to na wydajność.
huyz
4
@TimDown: najpierw napisz kod, który można odczytać. po drugie, napisz kod, który można utrzymać, a następnie, jeśli jest naprawdę spowolniony. pomyśl o wydajności.
andreas
4

Możesz także użyć operatora void, aby uzyskać niezdefiniowaną wartość:

if (input !== void 0) {
    // do stuff    
}

(I tak, jak zauważono w innej odpowiedzi, spowoduje to błąd, jeśli zmienna nie zostanie zadeklarowana, ale ten przypadek można często wykluczyć przez kontrolę kodu lub przez refaktoryzację kodu, np. Użycie window.input !== void 0do testowania zmiennych globalnych lub dodawanie var input).

Claude
źródło
1

Natknąłem się na to, jeśli (typeof input !== 'undefined')w tym scenariuszu jest on używany do zapewnienia domyślnych parametrów funkcji:

function greet(name, greeting) {
  name = (typeof name !== 'undefined') ?  name : 'Student';
  greeting = (typeof greeting !== 'undefined') ?  greeting : 'Welcome';

  return `${greeting} ${name}!`;
}

greet(); // Welcome Student!
greet('James'); // Welcome James!
greet('Richard', 'Howdy'); // Howdy Richard!

ES6 zapewnia nowe sposoby wprowadzania domyślnych parametrów funkcji w ten sposób:

function greet(name = 'Student', greeting = 'Welcome') {
  return `${greeting} ${name}!`;
}

greet(); // Welcome Student!
greet('James'); // Welcome James!
greet('Richard', 'Howdy'); // Howdy Richard!

Jest to mniej gadatliwe i czystsze niż pierwsza opcja.

JSpecs
źródło
1

function greet(name, greeting) {
  name = (typeof name !== 'undefined') ?  name : 'Student';
  greeting = (typeof greeting !== 'undefined') ?  greeting : 'Welcome';

  console.log(greeting,name);
}

greet(); // Welcome Student!
greet('James'); // Welcome James!
greet('Richard', 'Howdy'); // Howdy Richard!

//ES6 provides new ways of introducing default function parameters this way:

function greet2(name = 'Student', greeting = 'Welcome') {
//  return '${greeting} ${name}!';
console.log(greeting,name);
}

greet2(); // Welcome Student!
greet2('James'); // Welcome James!
greet2('Richard', 'Howdy'); // Howdy Richard!

Avinash Maurya
źródło
0

(function(){

  var a= b = 3;
  var ed = 103;
  
})();



//console.log(ed); //ed is not defined

console.log("a defined? " + (typeof a !== 'undefined')); //no define
console.log("b defined? " + (typeof b !== 'undefined')); //yes define
console.log(typeof(b)); //number
console.log(typeof(4+7));   //number
console.log(b); //3
console.log(typeof("4"+"7")); //string
var e= "ggg";
console.log(typeof(e)); //string
 var ty=typeof(b);
console.log(ty); //number
console.log(typeof false); //boolean
console.log(typeof 1); //number
console.log(typeof 0); //number
console.log(typeof true); //boolean


console.log(typeof Math.tan);  //function
console.log(typeof function(){}); //function 

if(typeof neverDeclared == "undefined") //no errors
if(typeof neverDeclared === "undefined") //no errors

//if(neverDeclared == null) //showing error 


console.log(typeof {a:1}); //object
console.log(typeof null); //object
console.log(typeof JSON); //object
console.log(typeof Math); //object
console.log(typeof /a-z/); //object
console.log(typeof new Date()); //object

console.log(typeof afbc); //undefined
//console.log(typeof new);//error

document.write("<br> * oprator as math ");
var r=14*"4";
document.write(r);

document.write("<br> + oprator as string ");
var r=14+"44";
document.write(r);

document.write("<br> Minus Operator work as mathematic ");
var r=64-"44";
document.write(r);


document.write("<br>");
console.log(typeof(4*"7")); //returns number
console.log(typeof(4+"7")); //returns string




 
Interview Question in JavaScript

Avinash Maurya
źródło
Czy możesz podać wyjaśnienie?
jhpratt GOFUNDME RELICENSING
Istnieje sześć możliwych wartości zwracanych przez typeof: obiekt, wartość logiczna, funkcja, liczba, łańcuch i niezdefiniowana. Operator typeof służy do uzyskania typu danych (zwraca ciąg) swojego operandu. Argumentem może być literał lub struktura danych, taka jak zmienna, funkcja lub obiekt. Operator zwraca typ danych. Typ składni operand lub typeof (operand)
Avinash Maurya,
0

var bar = null;
console.log(typeof bar === "object"); //true yes 
//because null a datatype of object

var barf = "dff";
console.log(typeof barf.constructor);//function


console.log(Array.isArray(bar));//falsss


console.log((bar !== null) && (bar.constructor === Object)); //false

console.log((bar !== null) && (typeof bar === "object"));  // logs false
//because bar!==null, bar is a object


console.log((bar !== null) && ((typeof bar === "object") || (typeof bar === "function"))); //false

console.log(typeof bar === typeof object); //false
console.log(typeof bar2 === typeof undefined); //true
console.log(typeof bar3 === typeof undefinedff); //true
console.log(typeof bar2 == typeof undefined); //true

console.log((bar !== null) && (typeof bar === "object") && (toString.call(bar) !== "[object Array]")); //false

Avinash Maurya
źródło
-7
if (input == undefined) { ... }

działa dobrze. To nie jest oczywiście w nullporównaniu, ale zwykle uważają, że jeśli trzeba rozróżniać undefinedi null, faktycznie raczej trzeba rozróżniać undefinedi byle wartość false, więc

else if (input) { ... }

czy to.

Jeśli program przedefiniuje undefined, to i tak jest naprawdę braindead.

Jedynym powodem, dla którego mogę wymyślić kompatybilność z IE4, nie zrozumiałem undefinedsłowa kluczowego (które nie jest tak naprawdę słowem kluczowym, niestety), ale oczywiście mogą to być wartości undefined, więc musiałeś to mieć:

var undefined;

a powyższe porównanie działałoby dobrze.

W drugim przykładzie prawdopodobnie potrzebujesz podwójnych nawiasów, aby uszczęśliwić kłaczki?

UniquePhoton
źródło
Twój input == undefinedpowróci truena nullwejściu.
mgol