typeof! == "undefined" vs.! = null

491

A menudo veo código JavaScript que comprueba parámetros indefinidos, etc. de esta manera:

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

Esto parece un poco despilfarrador, ya que implica tanto una búsqueda de tipo como una comparación de cadenas, sin mencionar su verbosidad. Sin undefinedembargo, es necesario porque podría renombrarse.

Mi pregunta es:
¿Cómo es ese código mejor que este enfoque?

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

Hasta donde sé, no puedes redefinir null, por lo que no se romperá inesperadamente. Y, debido a la coerción de tipo del !=operador, esto comprueba ambos undefinedy null... que a menudo es exactamente lo que desea (por ejemplo, para parámetros de función opcionales).

Sin embargo, esta forma no parece generalizada e incluso hace que JSLint te grite por usar el !=operador maligno .

¿Por qué esto se considera mal estilo?

Derek Thurn
fuente
13
@ Marcel, no hay una diferencia real, pero hay dos razones para hacerlo. Una, es que para algunos es más claro de leer. Y la segunda razón, es que evita la sobreescritura accidental de una variable. ¿Alguna vez has hecho esto: if (foo = "value") al intentar hacer una comparación? Si tiene el hábito de invertir la variable, en el operador de asignación / comparación, entonces no tendrá ese problema.
Layke
29
Para algunos (incluyéndome a mí) esto es realmente más difícil de leer. Además, la mayoría de los IDE le advierten sobre la asignación accidental. Pero todavía uso este formulario si la variable comparada es muy larga. YMMV.
johndodo
15
@MarcelKorpel Esto se llama "condición de Yoda": umumble.com/blogs/Programming/321
kol
55
Es más difícil de leer. Uno no dice "No está vacía la botella".
Noel Abrahams
11
if (null != input)es solo "Yoda Speak" para el hablante de inglés (de uno soy ... uuammmmm) así que si equivalen a lo mismo, en realidad es solo semántica. EN MI HUMILDE OPINIÓN.
webLacky3rdClass

Respuestas:

710

typeof es más seguro ya que permite que el identificador nunca se haya declarado antes:

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

if(neverDeclared === null) // throws ReferenceError: neverDeclared is not defined
seanmonstar
fuente
3
if ((typeof neverDeclared! == "undefined") && (neverDeclared! == null)) {return true; } else {return false; }
Anthony DiSanti
88
Use === al comparar con nulo / indefinido.
MyGGaN
47
@MyGGaN solo si desea distinguir entre los dos. En muchos casos, ==puede ser mejor, porque prueba tanto para nulo como para indefinido.
seanmonstar
10
No puedo encontrar ninguna diferencia entre typeof somevar == 'undefined' y typeof somevar === 'undefined', porque typeof siempre devuelve una cadena. Para nulo devolverá 'objeto'. ¿O podría ser que estoy equivocado?
TomTom
2
Creo que el comentario de @TomTom es el quid del problema: no puedo entender por qué uno usaría los operadores !==o ===al comparar un valor cuyo tipo se sabe que es una cadena.
Nicolas Rinaudo
49

Si se declara la variable (ya sea con la varpalabra clave, como un argumento de función o como una variable global), creo que la mejor manera de hacerlo es:

if (my_variable === undefined)

jQuery lo hace, así que es lo suficientemente bueno para mí :-)

De lo contrario, tendrá que usar typeofpara evitar a ReferenceError.

Si espera que se redefina lo indefinido, puede ajustar su código de esta manera:

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

O consígalo a través del voidoperador:

const undefined = void 0;
// also safe
Joey Adams
fuente
1
Si undefined ya se ha definido, ¿no lo pasarías a tu función anónima a través de un parámetro llamado undefined, sin lograr nada?
Anthony DiSanti
20
@Anthony DiSanti: No, undefinedes el nombre dado al parámetro de la función, no su valor. No se pasa nada a la función, lo que significa que el valor del primer parámetro no está definido.
Joey Adams
3
Ah, mi error, gracias por seguir. He eliminado mi voto, perdón por eso.
Anthony DiSanti
2
¿Por qué escribir una excepción para manejar la declaración indefinida de otro desarrollador cuando puede comenzar correctamente? jQuery envuelve la función anónima inicial como se muestra en su función para garantizar que no se haya definido indefinido y para disminuir el tamaño minimizado. En pocas palabras, si puede dar resultados inesperados al hacerlo de esta manera, ¿por qué arriesgarse por una programación diferida para evitar la tipificación (typeof variable === 'undefined'). ¿Qué pasaría si quisiéramos (typeof variable === 'object') deberíamos proporcionar una variable predeterminada que también sea un objeto para que podamos hacer (variable === object)?
fyrye
28

Buen camino:

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

Pero la mejor manera es verificar a través de:

if(typeof neverDeclared === typeof undefined) //also no errors and no strings
Broma
fuente
66
var undefined = function () {}; if (typeof neverDeclared === typeof undefined); neverDecalred! = 'función'; jsfiddle.net/hbPZ5 return typeof var; devuelve una cadena Sin errores ni cadenas, pero no siempre dará los resultados esperados. Los desarrolladores autorizados no deberían declarar indefinidos, pero hay algunos marcos y bibliotecas que sí lo hacen.
fyrye
1
Principalmente uso if (typeof neverDeclared === typeof undefined) { pero Lint arroja un error. "Esperaba una cadena y en su lugar vi 'typeof'". ¿Cómo evitarías este error? ¿Deberíamos someternos a las demandas de Lint y utilizar el "buen camino"?
Ayelis
2
@fyrye ¿Conoces alguna biblioteca / framework de JavaScript que realmente mute indefinido? Se que es posible; pero me gustaría encontrar un ejemplo salvaje de "¡Aquí es donde puedes encontrar a este ñu desagradable!"
bigtunacan
44
typeof neverDeclared === typeof void 0;-D
Alex Yaroshevich
1
Es propenso a errores, porque de hecho solo confía en una determinada variable ("indefinida") que no se define. Lo cual puede ser falso, como lo mostraron otras publicaciones. Siempre puedes hacerlo if(typeof neverDeclared === typeof undefined_variable_with_a_name_assumed_to_be_never_defined) {pero es bastante largo.
Pierre-Olivier Vares
12

Realmente no debería preocuparse por un nombre indefinido. Si alguien cambia el nombre de indefinido, tendrá muchos más problemas que unos pocos si los cheques fallan. Si realmente desea proteger su código, envuélvalo en un IFFE (expresión de función invocada inmediatamente) como este:

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

Si está trabajando con variables globales (que ya está mal) en un entorno de navegador, comprobaría si no está definido de esta manera:

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

Dado que las variables globales son parte del objeto de la ventana, simplemente puede verificar contra indefinido en lugar de convertir a una cadena y comparar cadenas.

Además de eso, ¿por qué sus variables no están definidas? He visto una gran cantidad de código en el que verifican la existencia de variables y realizan algunas acciones basadas en eso. Ni una sola vez he visto dónde este enfoque ha sido correcto.

Peeter
fuente
1
La validación de entrada y la verificación de dependencia son buenas razones para usar esto. Si tengo archivos Javascript que dependen de otros archivos que se han cargado o se han declarado objetos init, entonces es útil probar objetos o propiedades de los que un archivo depende contra indefinidos y lanzar una buena excepción en lugar de dejar que su script falle en algún lugar impredecible.
AmericanUmlaut
Parece que podría necesitar algo en la línea de AMD (require.js)
Peeter
1
O podría querer hacer una comparación muy simple en lugar de incluir otra biblioteca en mi proyecto :)
AmericanUmlaut
Demasiado tarde para editar :(. Quería agregar - require.js tampoco es la solución correcta para la validación de entrada (los objetos init que mencioné en mi comentario inicial). Si tiene un objeto que espera que se complete con cierta los valores antes de cargar el guión, entonces es útil para lanzar una excepción si no se definen.
AmericanUmlaut
1
No, porque typeof devuelve una cadena. Entonces typeof undefined devuelve "undefined". window.input! == undefined (si su variable está en el espacio global)
Peeter
5

Si está realmente preocupado por la redefinición de lo indefinido, puede protegerse contra esto con algún método auxiliar como este:

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

Esto funciona porque cuando alguien escribe undefined = "foo", solo deja que el nombre undefined haga referencia a un nuevo valor, pero no cambia el valor real de undefined.

Ivo Wetzel
fuente
1
Sin embargo, ahora ha introducido una llamada de función, que dañará el rendimiento.
Tim Down
No creo que esta llamada a la función mate el rendimiento, es mucho más probable que el DOM sea el cuello de botella. Pero de todos modos, si tiene su gran función anónima habitual que contiene su biblioteca, también puede definirla undefined_checken la parte superior y luego usarla en cualquier parte de su código.
Ivo Wetzel el
1
De acuerdo, y no digo que sea una mala idea. Vale la pena señalar que llamar a esta función funcionará más lentamente que hacer una typeofcomprobación.
Tim Down
Creo que esta función es lo suficientemente simple como para que esté en línea, de modo que el rendimiento no se vea afectado.
huyz
44
@TimDown: primer código de escritura, eso es legible. segundo código de escritura, que se puede mantener, y luego, si es realmente lento. luego piense en el rendimiento.
andreas
4

También puede usar el operador vacío para obtener un valor indefinido:

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

(Y sí, como se señaló en otra respuesta, esto arrojará un error si la variable no se declaró, pero este caso a menudo se puede descartar mediante inspección de código o refactorización de código, por ejemplo, window.input !== void 0para probar variables globales o agregar var input).

Claude
fuente
1

De hecho, me he encontrado si (typeof input !== 'undefined')en este escenario donde se usa para proporcionar parámetros de función predeterminados:

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 proporciona nuevas formas de introducir parámetros de función predeterminados de esta manera:

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

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

Esto es menos detallado y más limpio que la primera opción.

JSpecs
fuente
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
fuente
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
fuente
¿Puedes dar una explicación?
jhpratt GOFUNDME RELICENSING
Hay seis valores posibles que typeof devuelve: objeto, booleano, función, número, cadena e indefinido. El operador typeof se usa para obtener el tipo de datos (devuelve una cadena) de su operando. El operando puede ser una estructura literal o de datos, como una variable, una función o un objeto. El operador devuelve el tipo de datos. Sintaxis typeof operand o 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
fuente
-7
if (input == undefined) { ... }

funciona bien Por supuesto, no es una nullcomparación, pero generalmente encuentro que si necesito distinguir entre undefinedy null, en realidad prefiero distinguir entre undefinedy cualquier valor falso, entonces

else if (input) { ... }

lo hace.

Si un programa redefine undefined, de todos modos es realmente una muerte mental.

La única razón por la que puedo pensar es por la compatibilidad con IE4, no entendió la undefinedpalabra clave (que en realidad no es una palabra clave, desafortunadamente), pero por supuesto que los valores podrían serlo undefined , por lo que tenía que tener esto:

var undefined;

y la comparación anterior funcionaría bien.

En su segundo ejemplo, ¿probablemente necesite paréntesis dobles para hacer feliz a la pelusa?

UniquePhoton
fuente
Su input == undefinedvolverá trueen una nullentrada.
mgol