实际上,假设未定义未被覆盖,这在JavaScript中有多危险?


86

每当有人提到针对进行测试时undefined都会指出undefined不是关键字,因此可以将其设置为"hello",因此您应该 typeof x == "undefined"改用。这对我来说似乎很荒谬。没有人会这样做,如果这样做的话,就足够理由永远不使用他们编写的任何代码吧?

我发现了一个示例该示例不小心设置undefinednull,这是为了避免假设该undefined值未被覆盖而提供的理由。但是,如果他们这样做了,那么该错误将不会被发现,而且我看不出有什么更好的方法。

在C ++中,每个人都清楚地说这是合法的#define true false,但是没有人建议您避免true使用它0 == 0。您只是假设没有人会大胆地这样做,如果这样做了,就永远不要再信任他们的代码了。

这是否真的曾经咬过别人undefined(故意)指派给别人的人,并且破坏了您的代码,或者这更多是一种假想的威胁?我愿意借此机会使我的代码更具可读性。这真的是个坏主意吗?

重申一下,我不是在要求如何防止未分配的未定义内容。我已经看过那些技巧写了100遍了。我在问不使用这些技巧是多么危险。


7
我很高兴,但是我觉得给出的三个答案中的任何一个都不能很好地回答问题。我试图弄清楚我不是在要求重新链接我链接的答案,但这仍然是我得到的。如果即使不是我要的问题也被认为是不接受答案,请告诉我,我将继续接受!
Cosmologicon

1
我认为所有事实都在这里列出。因此,您要说的是,您想要一个主观的答案或意见,但这只会导致分歧。这就是问题标题中不允许使用“最佳实践”一词的原因。您是唯一知道自己的情况有多危险的人。而且,如果您正在编写一个流行的库,其中您不控制所有的“变量”,那么函数(未定义){}包装器似乎是一个很好的答案。为什么不使用它并接受该答案?
香农2012年

4
如果有人担心有人重新定义undefined,则应该更多地担心有人重新定义XMLHttpRequest,或者alert。我们使用的所有功能都window可以重新定义。而且,如果您只是担心同事无意间这样做,那为什么还要相信他们不要这样做window.addEventListener = "coolbeans"呢?答案是不必担心这些。如果有人恶意将JS注入到您的页面中,则无论如何您都会被抽水。首先要防止这种情况发生。
克里斯·米德尔顿

Answers:


56

不,我从来没有。这主要是因为我是在大多数符合ECMAScript 5的现代浏览器上进行开发的。ES5标准规定undefined现在是只读的。如果您使用严格模式(应该),那么如果您不小心尝试对其进行修改,则会引发错误。

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

你应该有什么不能做的是建立自己的作用域,可变undefined

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

常数很好。仍然没有必要,但是很好。

(function () {
    const undefined = void 0;
})();

您的第一条语句仅确保您不会在开发过程中意外覆盖未定义的语句,在客户端计算机上与其他代码一起运行时仍会构成相同的威胁。
bennedich 2012年

1
@bennedich:我知道,我是说我从未遇到过这个问题,但这是您应该做的
Ry-

1
@bennedich您是否有相同的机会意外覆盖任何其他变量?
Ates Goral

40

没有适当的代码会做这种事情。但是您永远无法知道您使用的是哪个智能型开发人员或插件/库/脚本。另一方面,这是极不可能的,现代浏览器根本不允许覆盖undefined,因此,如果您使用这种浏览器进行开发,您会很快注意到是否有任何代码试图覆盖它。


即使您没有要求-很多人在寻找更常见的“如何防止重新定义的undefined”问题时也会发现此问题,因此无论如何我都会回答:

无论浏览器有多老,都有一种非常好的获取真正未定义 undefined的方法:

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

之所以有效,是因为始终未指定参数undefined。您也可以使用接受一些实参的函数来完成此操作,例如在使用jQuery时就这样。以这种方式确保环境健全通常是一个好主意:

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

然后,您可以确保在该匿名函数中满足以下条件:

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

但是,请注意,有时typeof x === 'undefined'实际上是有必要的:如果x从未将变量设置为某个值(与设置为相反undefined),则以x其他方式进行读取(例如)if(x === undefined)将引发错误。但是,这不适用于对象属性,因此,如果您知道该y对象始终是对象,那if(y.x === undefined)是绝对安全的。


2
您关于x未设置为值的说法不太正确(请参阅jsfiddle.net/MgADz);而是实际上是否确实未定义它(请参阅jsfiddle.net/MgADz/1)。
Ry-

7
同样,如果有人不小心说undefined = someVariable那是一个错误,而您破坏一切。至少我知道。
Cosmologicon

2
我曾与一个代码库一起工作,该代码库有一个覆盖了未定义的缩小的遗留脚本,我们没有时间或预算来重写该脚本,这是一个需要typeof x ==“ undefined”的示例,这并不奇怪,可能一个好习惯。
Damen TheSifter

2
我对为什么所有示例在函数中使用“ undefined”作为附加参数感兴趣?但是,如果有人错误地传递了一个额外的参数(定义),并且所有逻辑都将失败,则可能会出现这种情况。为什么不使用像function()这样的东西?if(someVal == _undef){做某事}};
Oleksandr_DJ 2013年

4
@Oleksandr_DJ确实如此。做一个值,你知道的undefined,并分配到undefined的范围。如果您传递“太多”的参数,请不要undefined为改写留空。这会引起错误,并且是一种固有的非防御性模式,尤其是正如Lucero指出的那样,当有非常简单的替代方法来获得可靠undefined的范围值时,尤其如此。
鲁芬2014年

19

有一个简单的解决方案:与之比较void 0始终是不确定的。

请注意,您应避免这样==做,因为它可能会强迫值。使用===(和!==)代替。

也就是说,如果有人写了undefined变量,则可能会设置错误,=而不是与==进行比较undefined


海事组织,这是最好的答案。
Abhisekp 2015年

1
如您在兼容性表中所看到的,请考虑一下它foo === void 0可能不那么平滑,foo === undefined并且undefined现代浏览器(IE 9+)完全支持不可变。
Daniel AR Werner

3

只有您知道使用什么代码,因此知道它有多危险。这个问题无法以您已经说明的方式回答。

1)创建一个团队策略,禁止重新定义未定义,保留它以供更广泛使用。扫描现有代码以获取未定义的左侧分配。

2)如果您无法控制所有情况,则如果代码是在您或您的策略控制范围之外使用的,则显然您的答案是不同的。扫描确实使用脚本的代码。哎呀,如果您愿意的话,可以在网上扫描未定义的左分配的统计信息,但是我怀疑这样做对您有帮助,因为在这里直接寻求答案#1或#3更容易。

3)如果这个答案不够好,那可能是因为您再次需要一个不同的答案。也许您正在编写一个将在公司防火墙内使用的流行库,但是您无法访问调用代码。然后在此处使用其他较好的答案之一。请注意流行的jQuery库实践了声音封装,并且开始了:

(function( window, undefined ) {

只有您可以按照自己的特定方式回答问题。还有什么要说的?

编辑:PS,如果您真的想要我的意见,我会告诉您这根本不危险。任何可能导致缺陷的东西(例如分配给undefined,这显然是有据可查的冒险行为)本身就是缺陷。缺陷就是风险。但这只是在我的场景中,我有能力承担这种观点。正如我所建议的那样,我回答了我的用例问题。


3

针对未定义进行测试是安全的。正如您已经提到的。如果您获得了一些覆盖它的代码(这是非常可改进的),那么就不要再使用它了。

也许如果您要创建供公众使用的库,则可以使用某些技术来避免用户更改它。但是即使在这种情况下,这也是他们的问题,而不是您的库。



1

一点也不危险。仅当在ES3引擎上运行时,它才能被覆盖,并且不再可能被使用。


0

首先,如果您的代码损坏了,那可能不是因为您所说的其他开发人员“正试图成为一个混蛋”。

的确,这undefined不是关键字。但这全局级别的原始数据。它打算像这样使用(请参阅developer.mozilla.org上的“ undefined” ):

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

常见的替代方法(也来自MDN),我认为更好的方法是:

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

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

}

它有几个优点,显而易见(从注释中)是:当未声明x时,它不会触发异常。还值得注意的是,MDN还指出,在第一种情况下使用===over至关重要,==因为:

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
}

这是另一个经常被忽略的原因,为什么在所有情况下仅使用第二种替代方法可能会更好。

结论:用第一种方法编码是没有错的,并且肯定没有危险。您所看到的用作示例的参数(可以被覆盖)不是用编码替代项的最强参数typeof。但是使用typeof更强是出于一个特定的原因:未声明您的var时它不会引发异常。也可能会争辩说,使用==代替===是一个常见的错误,在这种情况下,它没有按照您的预期做。那么为什么不使用typeof呢?


1
“这有很多优点,显而易见的是,当未声明x时,它不会触发异常。” 让我说清楚。您认为静默忽略使用未声明的变量时发生的异常是一个优势吗?这似乎很容易出错。您能解释一下为什么您认为这不是一个可怕的劣势吗?
Cosmologicon
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.