在 JavaScript 中,假设未定义没有被覆盖是多么危险



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

我发现了一个不小心将undefined设置为 null 的例子,这是为了避免假设undefined没有被覆盖的原因。但是如果他们这样做了,这个错误就不会被发现,我看不出这有什么好。

在C++每个人都很清楚说#define true false是合法的,但没有人建议你避免true而改用0 == 0。你只是假设没有人会成为一个足够大的混蛋来做到这一点,如果他们这样做了,就再也不相信他们的代码了。

这是否曾经真正咬过其他人分配给undefined的人(故意(并且它破坏了您的代码,或者这更像是一种假设的威胁?我愿意冒险让我的代码更具可读性。这真的是一个坏主意吗?

重申一下,我不是在问如何防止重新分配的未定义。这些技巧我已经写了100次了。我问不使用这些技巧有多危险。

不,我从来没有。这主要是因为我在现代浏览器上开发,这些浏览器大多符合 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;
})();

没有适当的代码可以做这样的事情。但是你永远无法知道一些想要聪明的开发人员或你正在使用的插件/库/脚本做了什么。另一方面,这是极不可能的,现代浏览器根本不允许覆盖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)是完全安全的。

有一个简单的解决方案:与始终未定义的void 0进行比较。

请注意,应避免使用==,因为它可能会强制使用值。请改用===(和!==(。

也就是说,如果有人在将某些内容与undefined进行比较时编写=而不是==,则可能会错误地设置未定义的变量。

只有你知道你使用什么代码,因此它有多危险。这个问题不能以你澄清你想要回答的方式回答。

1(创建一个团队策略,不允许重新定义undefined,将其保留给更流行的使用。扫描现有代码以查找未定义的左分配。

2(如果你不能控制所有的场景,如果你的代码是在你或你的策略控制的情况下使用的,那么显然你的答案是不同的。扫描使用脚本的代码。哎呀,如果您愿意,可以扫描网络以获取未定义的左分配的统计信息,但我怀疑这已经为您完成了,因为在这里追求答案 #1 或 #3 更容易。

3(如果这个答案还不够好,那可能是因为,同样,你需要一个不同的答案。也许您正在编写一个将在公司防火墙中使用的流行库,并且您无权访问调用代码。然后在这里使用其他很好的答案之一。请注意流行的jQuery库实践声音封装,并开始:

(function( window, undefined ) {

只有你能以你所寻求的特定方式回答你的问题。还有什么好说的?

编辑:附言如果你真的想要我的意见,我会告诉你这根本不危险。 任何可能导致缺陷的东西(例如分配给未定义,这显然是一种有据可查的危险行为(本身就是缺陷。缺陷就是风险。但这只是在我的场景中,我可以持有这种观点。正如我推荐的那样,我回答了我的用例的问题。

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

也许如果您正在创建一个供公共使用的库,您可以使用一些技术来避免用户更改它。但即使在这种情况下,这也是他们的问题,而不是你的图书馆。

在为 ECMAScript 5.1 的浏览器编码时,您可以在代码中使用 undefined,因为根据语言规范,它是不可变的。

另请参阅此兼容性表或此 caniuse ECMAScript 5 以查看所有现代浏览器 (IE 9+( 都实现了不可变undefined

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

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

确实,undefined不是关键字。但它全局级别的原语。它打算像这样使用(请参阅 developer.mozilla.org 中的"未定义"(:

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 还指出,在第一种情况下使用 === 而不是 == 很重要,因为:

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呢?

最新更新