24

Why is there an isNaN() function in JavaScript whilst isUndefined() must be written as:

typeof(...) != "undefined"

Is there a point I don't see?

In my opinion its really ugly to write this instead of just isUndefined(testValue).

James Donnelly
  • 126,410
  • 34
  • 208
  • 218
MemLeak
  • 4,456
  • 4
  • 45
  • 84
  • 6
    Good question. But I think this one is better in Programmers SE (conceptual thing). Additionally, utility libs like Underscore have [`_.isUndefined`](http://underscorejs.org/#isUndefined) – Joseph Oct 17 '14 at 13:39
  • 4
    Very disappointed in stackoverflow. Nobody has bothered to read the question in full. – simonzack Oct 17 '14 at 13:47
  • 15
    @simonzack it's a silly question. Why *should* there be an `isUndefined()`? Why not an `isNull()` too? Or `isEmptyString()`? Or `is17()` for that matter? – Pointy Oct 17 '14 at 13:48
  • 3
    Note [`isNaN`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN) doesn't check if the argument is `NaN`. Instead, it checks if the argument coerced to number is `NaN`. If you want to check if the argument is `NaN`, you can use ES6 [`Number.isNaN`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN). – Oriol Oct 17 '14 at 19:03

4 Answers4

27

There is simply no need for an isUndefined() function. The reason behind this is explained in the ECMAScript specification:

(Note that the NaN value is produced by the program expression NaN.) In some implementations, external code might be able to detect a difference between various Not-a-Number values, but such behaviour is implementation-dependent; to ECMAScript code, all NaN values are indistinguishable from each other.

The isNaN() function acts as a way to detect whether something is NaN because equality operators do not work (as you'd expect, see below) on it. One NaN value is not equal to another NaN value:

NaN === NaN; // false

undefined on the other hand is different, and undefined values are distinguishable:

undefined === undefined; // true

If you're curious as to how the isNaN() function works, the ECMAScript specification also explains this for us too:

  1. Let num be ToNumber(number).
  2. ReturnIfAbrupt(num).
  3. If num is NaN, return true.
  4. Otherwise, return false.

A reliable way for ECMAScript code to test if a value X is a NaN is an expression of the form X !== X. The result will be true if and only if X is a NaN.

NaN !== NaN; // true
100 !== 100; // false

var foo = NaN;
foo !== foo; // true
Community
  • 1
  • 1
James Donnelly
  • 126,410
  • 34
  • 208
  • 218
  • 2
    That `NaN === NaN` is false is actually precisely why you don't need an `isNaN` either. As says the documentation you quote, testing for `NaN !== NaN` is entirely sufficient. Accordingly, it is not useful to say that `isUndefined()` does not exist because it's not needed because `isNaN()` does exist and is precisely as unuseful. – Lightness Races in Orbit Oct 17 '14 at 15:26
  • 11
    @LightnessRacesinOrbit not really. To compare for `NaN` the `isNaN()` function compares the value against itself. Calling `isNaN(myReallyLongObject.myReallyLongVariableName)` is much more desirable than calling `myReallyLongObject.myReallyLongVariableName !== myReallyLongObject.myReallyLongVariableName`. With `undefined`, you'd simply `myReallyLongObject.myReallyLongVariableName === undefined`. The check isn't `variable !== NaN`, it's `variable !== variable`. This would make things confusing to read, whereas the `isNaN()` method tells you exactly what is being checked for. – James Donnelly Oct 17 '14 at 15:29
  • @James, you should add that last part to your answer. As to why having a `isNaN()` function makes sense. People could put `x !== x` all over the place, but it may not be immediately clear just looking at it what the purpose of the check is and therefore carries greater risk of confusion and error in use. `isNaN()` is crystal clear. – Mr.Mindor Oct 17 '14 at 17:24
  • 1
    Note [`isNaN`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN) does NOT "detect whether something is `NaN`". Instead, it checks if something coerced to number is `NaN`. To detect whether something is `NaN`, ES6 [`Number.isNaN`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN) can be used instead. – Oriol Oct 17 '14 at 19:06
  • 3
    You have misunderstood the bolded clause. What happens is, IEEE 754 (which defines, among other things, the double-precision floating-point format) defines many different bit-patterns that are all NaNs -- and even gives somewhat different meanings to some of these bit-patterns. The bolded clause is explaining that ECMAScript does not provide any way to distinguish the different bit-patterns: all NaNs are equivalent and interchangeable. The fact that `NaN !== NaN` is a completely separate fact; the bolded clause could still be true in an alternate-universe ECMAScript where `NaN === NaN`. – ruakh Oct 17 '14 at 23:46
  • @LightnessRacesinOrbit: isNan("I am not a number") returns `true`, even though "I am not a number"==="I am not a number" also returns `true`. – supercat Oct 18 '14 at 03:46
  • @ruakh: I'm amazed how many languages seem to think the broken IEEE 754 equivalence relation is a good idea. I find the idea of testing something against itself for the purpose of checking `NaN` in any context outer than an `isNaN` function offensive; I'd much rather have a language with an equivalence operator that tests equivalence than have IEEE754 semantics. – supercat Oct 18 '14 at 03:50
  • @supercat: Indeed. Standard ML found the IEEE 754 semantics so unpalatable that it ended up changing `real` to not be an equality type anymore; `x = y` is now rejected by the compiler, and you have to use a special library function, `Real.==`, to declare that yes, you're really prepared for the weirdness of IEEE 754 semantics . . . – ruakh Oct 18 '14 at 04:59
  • @ruakh: Glad someone in this world had some sanity, though I think my inclination would be to have separate types for ieee32, ieee64, shortreal, midreal, and real; the first two would behave according to IEEE-754 semantics and disallow implicit conversions. The latter would be stored using IEEE 32, 64, and maximum-platform-precision (64 or 80) formats; operators that return floating-point types would return `real` regardless of the source type (so if all variables are `shortReal`, `sr1=sr2+sr3+sr4` would be evaluated at maximum precision and round the result). – supercat Oct 18 '14 at 17:05
  • @ruakh: I'd implement IEEE-style equality for the "ieee32" and "ieee64" types, and equivalence-based equality for the others [note, however, that the only promotions allowed with the equality-test operator would be lossless integer promotions; to when different values of different FP types, I would require code to cast one value to match the precision of the other, since neither direction of cast would be semantically correct in all cases]. – supercat Oct 18 '14 at 17:08
15

The use case var === undefined works almost everywhere, except for the cases covered by this answer, where either undefined is assigned a value, or var is undefined.

The reason such a function cannot exist, is clear from the latter case. If var is undefined, then calling the supposed function isUndefined(var) will result in a ReferenceError. However introducting a new keyword, e.g. isundefined var could address this issue.

But despite being valid, both of the above cases are poor uses of javascript. This is the reason I believe such a keyword does not exist.

Community
  • 1
  • 1
simonzack
  • 19,729
  • 13
  • 73
  • 118
  • You can get around the *if var is `undefined`* issue by referencing an existing scope in which the variable is present. If the variable is global, we can check whether it's undefined by passing in `window.foo` or `window['foo']` (where `foo` is our undefined variable) rather than just `foo` by itself. Here is our function: `function isUndefined(val) { return val === undefined; }`, here is our test: `isUndefined(window.foo);` The result will be `true`, as there is no global `foo` variable defined. – James Donnelly Oct 17 '14 at 14:17
  • @JamesDonnelly That is equivalent to `window.foo === undefined`, which imo doesn't really answer the question, which asks for an alternative to the `typeof` method. – simonzack Oct 17 '14 at 14:20
  • 9
    The reason `isUndefined()` doesn't exist is because it isn't necessary. As Pointy replied to your comment on the question, if we have an `isUndefined()` why don't we also have an `isNull()` or `is17()`. `isNaN()` is a necessity, as NaN values are indistinguishable from each other. `NaN` is not equal to `NaN`. `undefined`, on the other hand, *is* equal to `undefined`. – James Donnelly Oct 17 '14 at 14:23
  • How is it not completely true? `undefined` is equal to `undefined`. Your answer completely ignores the fact that `typeof undefinedvariable` returns "undefined". – James Donnelly Oct 17 '14 at 14:28
  • @JamesDonnelly I don't think we're interpreting OPs question the same way. I'm interpreting it as why there isn't an `isUndefined(testValue)` equivalent to `typeof(testValue) != "undefined"`. – simonzack Oct 17 '14 at 14:31
  • 1
    The title of the question asks why `isNaN()` exists but `isUndefined()` doesn't exist. Your answer doesn't mention `NaN` at all and why `isNaN()` is part of ECMAScript, it instead makes assumptions on why `isUndefined()` isn't part of ECMAScript. `isNaN()` is a required function as there are no other (simple) ways of comparing a value to `NaN`. `undefined` on the other hand, can be determined using the equality operators `==` and `===`, so such a function isn't at all necessary. – James Donnelly Oct 17 '14 at 14:35
  • @JamesDonnelly You are right about why `isNaN()` must exist, and why `isUndefined()` is not necesarry, but I believe OPs focus here is on why `isUndefined()` cannot exist as a convenience function, not on `isNaN()`. – simonzack Oct 17 '14 at 14:39
  • 5
    @JamesDonnelly `isNaN` is very easily implemented, so your argument for why it must exist is flawed. `function isNaN(x){return x !== x;}` - the fact that its the only thing not equal to itself is how it can be identified. – Aaron Dufour Oct 17 '14 at 15:40
  • 2
    @AaronDufour but you'd have to define this function in every project you create where you need to check whether a value is `NaN`. As I've mentioned before, checking for `undefined` is as simple as `value === undefined`, whereas checking for NaN isn't as simple as `value === NaN`. The `isNaN()` function is much more useful than an `isUndefined()` function would be. Equally, by your logic, why should any functions be pre-defined in ECMAScript when we can just write them ourselves? :-) Remember, this was something decided on by the creators of ECMAScript and the editors of ECMAScript 6, not me. – James Donnelly Oct 17 '14 at 15:43
  • 5
    @JamesDonnelly I agree with everything you've said there, but there's still no defense for "`isNaN()` is a necessity" from your earlier comment. Its a convenience, at best - definitely not a necessity. – Aaron Dufour Oct 17 '14 at 15:53
  • @simonzack You talk about `var` being undefined at several points; I _think_ you actually mean undeclared. – doppelgreener Oct 18 '14 at 07:00
4

isUndefined could be written as

testValue === undefined

like for every other value.

This does not work with NaN however, as NaN !== NaN. Without the ability to use a comparison, there was need for an isNaN function to detect NaN values.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

This isn't a direct answer to the question as others have already answered, it's more to highlight libraries that contain an isUndefined() function for anybody looking for quick solution and they're in a position to use them.

Underscore and Lo-dash both contain an isUndefined() function, the latter, because it's built upon Underscore.

SteveA
  • 456
  • 6
  • 14