typeof! == «non défini» vs! = null

491

Je vois souvent du code JavaScript qui vérifie les paramètres non définis, etc. de cette façon:

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

Cela semble un peu inutile, car cela implique à la fois une recherche de type et une comparaison de chaînes, sans parler de sa verbosité. Il est nécessaire car il undefinedpourrait être renommé.

Ma question est:
comment ce code est-il meilleur que cette approche:

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

Pour autant que je sache, vous ne pouvez pas redéfinir null, donc ça ne va pas se casser de façon inattendue. Et, en raison de la coercition de type de l' !=opérateur, cela vérifie les deux undefinedet null... qui est souvent exactement ce que vous voulez (par exemple pour les paramètres de fonction facultatifs).

Pourtant, ce formulaire ne semble pas répandu, et il fait même que JSLint vous crie pour avoir utilisé l' !=opérateur maléfique .

Pourquoi est-ce considéré comme un mauvais style?

Derek Thurn
la source
13
@ Marcel, il n'y a pas vraiment de différence, mais il y a deux raisons de le faire. Premièrement, il est plus clair à lire pour certains. Et la deuxième raison, c'est qu'elle empêche l'écrasement accidentel d'une variable. L'avez-vous déjà fait: if (foo = "value") lorsque vous avez l'intention de faire une comparaison. Si vous prenez l'habitude d'inverser la variable, dans l'opérateur d'affectation / comparaison, vous n'aurez pas ce problème.
Layke
29
Pour certains (dont moi), c'est en fait plus difficile à lire. De plus, la plupart des IDE vous avertissent d'une affectation accidentelle. Mais j'utilise toujours ce formulaire si la variable comparée est très longue. YMMV.
johndodo
15
@MarcelKorpel C'est ce qu'on appelle la "condition Yoda": umumble.com/blogs/Programming/321
kol
55
C'est plus difficile à lire. On ne dit pas "La bouteille n'est pas vide".
Noel Abrahams
11
if (null != input)est seulement "Yoda Speak" pour le locuteur anglais (De celui que je suis .... uuammmmm) donc s'ils équivalent à la même chose c'est vraiment juste de la sémantique. A MON HUMBLE AVIS.
webLacky3rdClass

Réponses:

710

typeof est plus sûr car il permet à l'identifiant de ne jamais avoir été déclaré auparavant:

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

if(neverDeclared === null) // throws ReferenceError: neverDeclared is not defined
seanmonstar
la source
3
if ((typeof neverDeclared! == "undefined") && (neverDeclared! == null)) {return true; } else {return false; }
Anthony DiSanti
88
Utilisez === lors de la comparaison avec null / indéfini.
MyGGaN
47
@MyGGaN uniquement si vous souhaitez faire la distinction entre les deux. Dans de nombreux cas, ==peut être meilleur, car il teste à la fois null et indéfini.
seanmonstar
10
Je ne trouve aucune différence entre typeof somevar == 'undefined' et typeof somevar === 'undefined', car typeof renvoie toujours une chaîne. Pour null, il retournera 'object'. Ou est-ce que je me trompe?
TomTom
2
Je crois que le commentaire de @ TomTom est au cœur du problème - je ne comprends pas pourquoi on utiliserait les opérateurs !==ou ===lors de la comparaison d'une valeur dont le type est connu pour être une chaîne.
Nicolas Rinaudo
49

Si la variable est déclarée (soit avec le varmot - clé, comme argument de fonction, soit comme variable globale), je pense que la meilleure façon de le faire est:

if (my_variable === undefined)

jQuery le fait, donc c'est assez bon pour moi :-)

Sinon, vous devrez utiliser typeofpour éviter a ReferenceError.

Si vous vous attendez à ce que undefined soit redéfini, vous pouvez envelopper votre code comme ceci:

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

Ou obtenez-le via l' voidopérateur:

const undefined = void 0;
// also safe
Joey Adams
la source
1
Si undefined a déjà été défini, ne le transmettriez-vous pas à votre fonction anonyme via un paramètre nommé undefined, sans rien faire?
Anthony DiSanti
20
@Anthony DiSanti: Non, undefinedc'est le nom donné au paramètre de fonction, pas sa valeur. Rien n'est transmis à la fonction, ce qui signifie que la valeur du premier paramètre n'est pas définie.
Joey Adams
3
Ah mon erreur, merci pour le suivi. J'ai supprimé mon vote, désolé.
Anthony DiSanti
2
Pourquoi écrire une exception pour gérer un non défini déclaré par un autre développeur alors que vous pouvez le faire correctement pour commencer? jQuery encapsule la fonction anonyme initiale comme vous l'affichez dans votre fonction pour vous assurer que non défini n'a pas été défini et pour réduire la taille réduite. Autrement dit, si cela peut donner des résultats inattendus pour le faire de cette façon, pourquoi le risquer pour une programmation paresseuse pour éviter de taper (typeof variable === 'undefined'). Et si nous voulions (typeof variable === 'objet') devrions-nous fournir une variable par défaut qui est également un objet afin que nous puissions le faire (variable === objet)?
fyrye
28

bonne façon:

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

Mais le meilleur moyen est de vérifier via:

if(typeof neverDeclared === typeof undefined) //also no errors and no strings
Blague
la source
6
var undefined = function () {}; if (typeof neverDeclared === typeof undefined); neverDecalred! = 'fonction'; jsfiddle.net/hbPZ5 return typeof var; renvoie une chaîne. Aucune erreur ou chaîne mais ne donnera pas toujours les résultats attendus. Les développeurs autorisés ne doivent pas déclarer non définis, mais il existe certains cadres et bibliothèques qui le font.
fyrye
1
J'utilise principalement if (typeof neverDeclared === typeof undefined) { mais Lint lance une erreur. "Attendu une chaîne et vu à la place 'typeof'." Comment contourneriez-vous cette erreur? Devrions-nous nous soumettre aux demandes de Lint et utiliser à la place la «bonne voie»?
Ayelis
2
@fyrye Connaissez-vous des bibliothèques / frameworks JavaScript qui mutent réellement non définis? Je sais que c'est possible; mais j'aimerais en trouver un dans l'exemple sauvage de "Voici où vous pourriez rencontrer ce méchant Gnou!"
bigtunacan
4
typeof neverDeclared === typeof void 0;-D
Alex Yaroshevich
1
Elle est sujette aux erreurs, car en fait, vous comptez simplement sur une certaine variable ("non définie") qui n'est pas définie. Ce qui peut être faux, comme l'ont montré d'autres articles. On peut toujours le faire if(typeof neverDeclared === typeof undefined_variable_with_a_name_assumed_to_be_never_defined) {mais c'est assez long.
Pierre-Olivier Vares
12

Vous ne devriez pas vraiment vous soucier de renommer undefined. Si quelqu'un renomme indéfini, vous aurez beaucoup plus de problèmes que quelques-uns si les contrôles échouent. Si vous voulez vraiment protéger votre code, enveloppez-le dans une IFFE (expression de fonction immédiatement invoquée) comme ceci:

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

Si vous travaillez avec des variables globales (ce qui est déjà faux) dans un environnement de navigateur, je vérifierais pour undefined comme ceci:

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

Étant donné que les variables globales font partie de l'objet fenêtre, vous pouvez simplement vérifier par non défini au lieu de transtyper en chaîne et de comparer des chaînes.

En plus de cela, pourquoi vos variables ne sont-elles pas définies? J'ai vu beaucoup de code où ils vérifient l'existence d'une variable et effectuent une action basée sur cela. Pas une seule fois je n'ai vu où cette approche était correcte.

Peeter
la source
1
La validation des entrées et la vérification des dépendances sont deux bonnes raisons de l'utiliser. Si j'ai des fichiers Javascript qui dépendent d'autres fichiers ayant été chargés ou que des objets init ont été déclarés, il est utile de tester des objets ou des propriétés dont un fichier dépend par rapport à undefined et de lancer une belle exception au lieu de laisser votre script échouer quelque part imprévisible.
AmericanUmlaut
On dirait que vous pourriez avoir besoin de quelque chose dans les lignes d'AMD (require.js)
Peeter
1
Ou je pourrais juste vouloir faire une comparaison très simple plutôt que d'inclure une autre bibliothèque dans mon projet :)
AmericanUmlaut
Trop tard pour éditer :(. Je voulais ajouter - require.js n'est pas non plus la bonne solution pour la validation des entrées (les objets init que j'ai mentionnés dans mon commentaire initial). Si vous avez un objet que vous vous attendez à remplir avec certains avant le chargement du script, alors il est utile de lever une exception si elles ne sont pas définies.
AmericanUmlaut
1
Non, car typeof renvoie une chaîne. Donc typeof undefined renvoie "undefined". window.input! == undefined (si votre variable est dans le spoce global)
Peeter
5

Si vous êtes vraiment inquiet de la redéfinition d'undefined, vous pouvez vous protéger contre cela avec une méthode d'assistance comme celle-ci:

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

Cela fonctionne parce que lorsque quelqu'un écrit, undefined = "foo"il ne laisse que le nom faire undefined référence à une nouvelle valeur, mais il ne change pas la valeur réelle de undefined.

Ivo Wetzel
la source
1
Cependant, vous avez maintenant introduit un appel de fonction, ce qui nuira aux performances.
Tim Down le
Je ne pense pas que cet appel de fonction va tuer les performances, il est beaucoup plus probable que le DOM soit le goulot d'étranglement. Mais de toute façon, si vous avez votre grande fonction anonyme habituelle qui contient votre bibliothèque, vous pouvez également définir undefined_checken haut et ensuite simplement l'utiliser partout dans votre code.
Ivo Wetzel du
1
D'accord, et je ne dis pas que c'est une mauvaise idée. Il convient de souligner que l'appel de cette fonction sera plus lent que la typeofvérification.
Tim Down du
Je pense que cette fonction est suffisamment simple pour être intégrée, donc les performances ne seront pas affectées.
huyz
4
@TimDown: écrivez d'abord le code, c'est lisible. deuxième code d'écriture, c'est maintenable, puis, si c'est vraiment trop lent. alors pensez à la performance.
andreas
4

Vous pouvez également utiliser l'opérateur void pour obtenir une valeur non définie:

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

(Et oui, comme indiqué dans une autre réponse, cela générera une erreur si la variable n'a pas été déclarée, mais ce cas peut souvent être exclu soit par inspection de code, soit par refactorisation de code, par exemple en utilisant window.input !== void 0pour tester des variables globales ou en ajoutant var input.)

Claude
la source
1

J'ai en fait rencontré si (typeof input !== 'undefined')dans ce scénario où il est utilisé pour fournir des paramètres de fonction par défaut:

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 propose de nouvelles façons d'introduire les paramètres de fonction par défaut de cette façon:

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

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

C'est moins verbeux et plus propre que la première option.

JSpecs
la source
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
la source
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
la source
Pouvez-vous fournir une explication?
jhpratt GOFUNDME RELICENSING
Il y a six valeurs possibles que typeof renvoie: objet, booléen, fonction, nombre, chaîne et non défini. L'opérateur typeof est utilisé pour obtenir le type de données (retourne une chaîne) de son opérande. L'opérande peut être soit un littéral, soit une structure de données telle qu'une variable, une fonction ou un objet. L'opérateur renvoie le type de données. Syntaxe typeof operand ou 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
la source
-7
if (input == undefined) { ... }

fonctionne très bien. Ce n'est bien sûr pas une nullcomparaison, mais je trouve généralement que si j'ai besoin de distinguer entre undefinedet null, j'ai plutôt besoin de distinguer entre undefinedet n'importe quelle valeur fausse, donc

else if (input) { ... }

le fait.

Si un programme redéfinit, undefinedil est vraiment braindead de toute façon.

La seule raison pour laquelle je peux penser était pour la compatibilité IE4, il ne comprenait pas le undefinedmot - clé (qui n'est pas réellement un mot-clé, malheureusement), mais bien sûr les valeurs pouvaient l' être undefined , donc vous deviez avoir ceci:

var undefined;

et la comparaison ci-dessus fonctionnerait très bien.

Dans votre deuxième exemple, vous avez probablement besoin de doubles parenthèses pour faire plaisir aux peluches?

UniquePhoton
la source
Vous input == undefinedreviendrez truesur une nullentrée.
mgol