97

Every time anyone mentions testing against undefined, it's pointed out that undefined is not a keyword so it could be set to "hello", so you should use typeof x == "undefined" instead. This seems ridiculous to me. Nobody would ever do that, and if they did it would be reason enough to never use any code they wrote... right?

I found one example of someone who accidentally set undefined to null, and this was given as a reason to avoid assuming that undefined isn't overwritten. But if they'd done that, the bug would have gone undetected, and I fail to see how that's better.

In C++ everyone is well aware that it's legal to say #define true false, but nobody ever advises you avoid true and use 0 == 0 instead. You just assume that nobody would ever be a big enough jerk to do that, and if they do, never trust their code again.

Has this ever actually bitten somebody where someone else assigned to undefined (on purpose) and it broke your code, or is this more of a hypothetical threat? I'm willing to take my chances to make my code marginally more readable. Is this a really bad idea?

To reiterate, I am not asking for how to protect against reassigned undefined. I've seen those tricks written 100 times already. I'm asking how dangerous it is to not use those tricks.

Community
  • 1
  • 1
Cosmologicon
  • 2,127
  • 1
  • 16
  • 18
  • 8
    I would be happy to, but I don't feel like any of the three answers given does a good job of answering the question. I tried to make it clear I wasn't asking for a rehash of the answers I linked to, but that's still what i got. If it's considered gauche not to accept an answer even if it's not what I was asking, let me know and I'll go ahead and accept one! – Cosmologicon May 19 '12 at 00:50
  • 1
    I think all the facts are laid out here, though. So, what you are saying is you want a subjective answer or opinion instead, which only leads to disagreement. It's the reason the phrase "best practice" is not allowed in question titles. You are the only person who can know how dangerous it is in your scenario. And if you are writing a popular library where you don't control all the 'variables', the function(undefined){} wrapper seems to be an excellent answer. Why not use it and accept that answer? – shannon Jul 19 '12 at 03:59
  • 4
    If anyone's worried about someone redefining `undefined`, you should worry more about someone redefining `XMLHttpRequest`, or `alert`. All the functions we use from `window` could have been redefined. And if you're just worried about a coworker doing it by accident, why trust them not to do `window.addEventListener = "coolbeans"`? The answer is not to worry about any of that. If someone is maliciously injecting JS into your page, you're hosed anyway. Work on preventing *that* from happening in the first place. – Chris Middleton Feb 13 '15 at 22:21

8 Answers8

61

No, I never have. This is mostly because I develop on modern browsers, which are mostly ECMAScript 5 compliant. The ES5 standard dictates that undefined is now readonly. If you use strict mode (you should), an error will be thrown if you accidentally try to modify it.

undefined = 5;
alert(undefined); // still undefined
'use strict';
undefined = 5; // throws TypeError

What you should not do is create your own scoped, mutable undefined:

(function (undefined) {
    // don't do this, because now `undefined` can be changed
    undefined = 5;
})();

Constant is fine. Still unnecessary, but fine.

(function () {
    const undefined = void 0;
})();
Ry-
  • 218,210
  • 55
  • 464
  • 476
  • Your first statement only assures you don't accidentally overwrite undefined while developing, it still poses the same threat when running with other code on client computers. – bennedich Jan 09 '12 at 03:22
  • 1
    @bennedich: I know, I was saying I've never run into that problem, but *here's what you should do*. – Ry- Jan 09 '12 at 03:24
  • 1
    @bennedich Don't you have the same chance of accidentally overwriting any other variable? – Ates Goral Jan 13 '16 at 21:40
40

No proper code will do such a thing. But you can never know what some wannabe-smart developer or a plugin/library/script you are using did. On the other side, it's extremely unlikely and modern browsers will not allow overwriting undefined at all, so if you are using such a browser for development you'll quickly notice if any code tries to overwrite it.


And even though you did not ask for it - many people will probably find this question when looking for the more common "how to protect against redefined undefined" issue, so I'll answer that anyway:

There's a very good way to get a truly undefined undefined no matter how old the browser is:

(function(undefined) {
    // your code where undefined is undefined
})();

This works because an argument that is not specified is always undefined. You can also do it with a function that accepts some real arguments, e.g. like this when you are using jQuery. It's usually a good idea to ensure a sane environment in this way:

(function($, window, undefined) {
    // your code where undefined is undefined
})(jQuery, this);

Then you can be sure that inside that anonymous function the following things are true:

  • $ === jQuery
  • window === [the global object]
  • undefined === [undefined].

However, note that sometimes typeof x === 'undefined' is actually necessary: If the variable x has never been set to a value (contrary to being set to undefined), reading x in a different way such as if(x === undefined) will throw an error. This does not apply to object properties though, so if you know that y is always an object, if(y.x === undefined) is perfectly safe.

ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
  • 2
    Your statement about `x` not being set to a value isn't quite true (see http://jsfiddle.net/MgADz/); it's rather if it's actually truly *not defined* (see http://jsfiddle.net/MgADz/1/). – Ry- Jan 09 '12 at 03:27
  • See my answer about getting the real undefined value as constant which cannot be changed by mistake (your `undefined` parameter may be changed if `=` was typed in instead of `==` or `===` when comparing against undefined. – Lucero Jan 09 '12 at 03:27
  • @Lucero: How many people do you see accidentally typing `undefined = someVariable`? You usually go the other way... `someVariable === undefined`. – Ry- Jan 09 '12 at 03:43
  • The best part about this is that it minifies quite well. – Peter C Jan 09 '12 at 07:00
  • @minitech: Some people (especially ones coming from a C background) do put the constants before the variables in predicates, exactly for this reason (preventing accidental assignment). e.g. `if (1 == flag) {` etc. - those may just as well put `undefined` in front of the predicate expression. – Lucero Jan 09 '12 at 16:39
  • Doesn't make it nicer - especially since gcc nowadays complains if you do `if(x = y)` unless you explicitely do `if((x = y))` – ThiefMaster Jan 09 '12 at 17:35
  • 7
    Again, if somebody accidentally says `undefined = someVariable` that's a bug and you _want_ things to break. At least I do. – Cosmologicon Jan 09 '12 at 18:51
  • @Cosmologicon: Well, develop in Google Chrome, Firefox, Safari, or IE9+ and you should be okay. – Ry- Jan 09 '12 at 20:34
  • A bit off topic but why does the closure in jQuery actually has a `window` parameter? – js-coder Jan 10 '12 at 15:07
  • To ensure `window` was not overwritten by something else. Since `window` is the global object and `this` points to the global object in the global context, passing `this` as an argument is a good way to ensure `window === the global object` – ThiefMaster Jan 10 '12 at 16:34
  • 2
    I have worked with a codebase that had a minified legacy script that overwrote undefined, we didn't have time or budget to rewrite the script, this is an example where typeof x == "undefined" was required, it's not that strange and probably a good habit. – Damen TheSifter Feb 07 '12 at 19:41
  • 2
    I am interested in why all examples use "undefined" as additional argument in function? But there can be situation if someone pass one extra param (defined) by error and all logic will be fail. Why not use something like function() { var _undef; if( someVal == _undef) {do something} }; – Oleksandr_DJ Sep 20 '13 at 15:57
  • Because `undefined` is `undefined`. Why would you start using something completely different just because some idiot might have redefined `undefined`? – ThiefMaster Sep 20 '13 at 17:23
  • 4
    @Oleksandr_DJ Exactly. Make up a value that you *know* is `undefined` and assign that to `undefined` in scope. **Don't leave `undefined` open for overwriting if you pass in "too many" arguments.** That invites errors, and is an inherently non-defensive pattern, especially when, as [Lucero points out](http://stackoverflow.com/a/8783534/1028230), there are very easy alternatives to get solid `undefined` values in scope. – ruffin Nov 20 '14 at 14:46
18

There's a simple solution to that: compare against void 0 which is always undefined.

Note that you should avoid == as it may coerce the values. Use === (and !==) instead.

That said, the undefined variable may be set by error if someone writes = instead of == when comparing something against undefined.

Lesmana
  • 25,663
  • 9
  • 82
  • 87
Lucero
  • 59,176
  • 9
  • 122
  • 152
  • IMO, this is the best answer. – abhisekp Aug 29 '15 at 17:53
  • 1
    Consider that `foo === void 0` might not read as smooth as `foo === undefined` and that immutable `undefined` is fully supported by modern browsers (IE 9+) as you can see in [this](http://kangax.github.io/compat-table/es5/#test-Immutable_undefined) compatibility table. – Daniel A. R. Werner Jan 13 '16 at 21:31
3

Only you know what code you use, and therefore how dangerous it is. This question can't be answered in the way you've clarified you want it answered.

1) Create a team policy, disallow redefining undefined, reserving it for its more popular usage. Scan your existing code for undefined left assignment.

2) If you don't control all the scenarios, if your code is used outside situations you or your policies control, then obviously your answer is different. Scan the code that does use your scripts. Heck, scan web for statistics of undefined left assignment if you wish, but I doubt that's been done for you, because it's easier to just pursue answer #1 or #3 here instead.

3) And if that answer isn't good enough, it's probably because, again, you require a different answer. Maybe you are writing a popular library that will be used inside corporate firewalls, and you don't have access to the calling code. Then use one of the other fine answers here. Note the popular jQuery library practices sound encapsulation, and begins:

(function( window, undefined ) {

Only you can answer your question in the specific way you seek. What more is there to say?

edit: p.s. if you really want my opinion, I'll tell you it's not dangerous at all. Anything that would be so likely to cause defects (such as assigning to undefined, which is obviously a well-documented risky behaviour) is itself a defect. It's the defect that is the risk. But that's just in my scenarios, where I can afford to hold that perspective. As I'd recommend you do, I answered the question for my use-cases.

shannon
  • 8,664
  • 5
  • 44
  • 74
3

It's safe to test against undefined. As you already mention. If you get to some code that overrides it (which is highly improvable), just don't use it anymore.

Maybe if you are creating a library for public use, you can use some of the techniques to avoid the user change it. But even in this case, it's their problem, not your library.

Bart Calixto
  • 19,210
  • 11
  • 78
  • 114
2

You can use undefined in your code when coding for browsers supporting ECMAScript 5.1 as it is immutable according to the language specification.

Also see this compatibility table or this caniuse ECMAScript 5 to see that all modern browsers (IE 9+) have implemented immutable undefined.

1

It's not dangerous at all. It can only be overwritten when running on an ES3 engine and that's not likely to be used any more.

kirk.burleson
  • 1,211
  • 2
  • 18
  • 29
0

First of all, if your code breaks it's probably not because some other developer out there "is trying to be a jerk" as you put it.

It's true that undefined is not a keyword. But it is a global level primitive. It was intended to be used like this (see "undefined" at developer.mozilla.org):

var x;
if (x === undefined) {
    // these statements execute
}
else {
    // these statements do not execute
}

The common alternative to that (also from MDN) and in my opinion the better way is:

// x has not been declared before
if (typeof x === 'undefined') { // evaluates to true without errors
    // these statements execute
}

if(x === undefined){ // throws a ReferenceError

}

Which has a couple of advantages, the obvious one (from the comments) is that it does not trigger an exception when x is not declared. It's also worth noting that MDN also points out that it is important to use === over == in the first case because:

var x=null;
if (x === undefined) {
    // this is probably what you meant to do
    // these lines will not execute in this case
}
else if (x == undefined) {
    // these statements will execute even though x *is* defined (as null)
}
else {
    // these statements do not execute
}

This is another often overlooked reason why it is probably better to just use the second alternative in all cases.

Conclusion: It's not wrong to code it the first way, and certainly not dangerous. The argument you've seen that you use as an example against it (that it can be overwritten) is not the strongest argument for coding the alternative with typeof. But using typeof is stronger for one reason specifically: it doesn't throw an exception when your var is not declared. It could also be argued that using == instead of === is a common mistake in which case it's not doing what you expected it to. So why not use typeof?

Octopus
  • 8,075
  • 5
  • 46
  • 66
  • 2
    "Which has a couple of advantages, the obvious one is that it does not trigger an exception when x is not declared." Let me get this straight. You think it's an *advantage* to silently ignore the exception that happens when you use an undeclared variable? That seems very error prone. Can you explain why you think that's not a terrible disadvantage? – Cosmologicon Dec 10 '15 at 02:17