在 JavaScript 中,假设未定义的内容没有被覆盖,这到底有多危险?

每次有人提到对 undefined已经指出来了进行测试时,undefined不是一个关键字,所以是 可以设成 "hello",所以是 你应该用 typeof x == "undefined"。我觉得这很荒谬。没有人会这么做,如果他们这么做了,就有足够的理由不用他们写的任何代码了,对吧?

我发现有人谁意外地设置 undefinednull举个例子,这是作为一个理由,以避免假设 undefined没有覆盖。但如果他们这么做了,窃听器就不会被发现了,我不知道这样好不好。

在 C + + 中,每个人都知道说 #define true false是合法的,但是从来没有人建议你避免使用 true而改用 0 == 0。你只是假设没有人会是一个大混蛋,这样做,如果他们这样做,永远不要相信他们的代码了。

这是否曾经真的咬过别人(故意)被分配到 undefined并且破坏了你的代码,或者这只是一个假设的威胁?我愿意抓住机会使我的代码稍微更具可读性。这真的是个坏主意吗?

重申一下,我是 没有,询问如何防止未定义的重新分配。这些把戏我已经看了一百遍了。我是问不使用这些伎俩有多危险。

11101 次浏览

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;
})();

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.

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.

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.

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.

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.

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?

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.