如何检查JavaScript中的对象属性是否未定义?
当前回答
这里的许多答案都强烈推荐typeof,但typeof是一个糟糕的选择。它不应用于检查变量是否具有未定义的值,因为它充当了未定义值和变量是否存在的组合检查。在绝大多数情况下,您知道变量何时存在,如果您在变量名称或字符串文字“undefined”中键入了错误,typeof可能会导致无声失败。
var snapshot = …;
if (typeof snaposhot === 'undefined') {
// ^
// misspelled¹ – this will never run, but it won’t throw an error!
}
var foo = …;
if (typeof foo === 'undefned') {
// ^
// misspelled – this will never run, but it won’t throw an error!
}
因此,除非您正在进行功能检测²,否则给定名称是否在范围内存在不确定性(例如检查typeof module!=='undefined'作为CommonJS环境特定代码的一个步骤),否则在变量上使用typeof是一个有害的选择,正确的选择是直接比较值:
var foo = …;
if (foo === undefined) {
⋮
}
对此,一些常见的误解包括:
读取“未初始化”变量(varfoo)或参数(函数栏(foo){…},称为bar())将失败。这根本不是真的——没有显式初始化的变量和没有给定值的参数总是未定义,并且总是在范围内。可以覆盖未定义的。的确,undefined不是关键字,但它是只读的,不可配置。尽管有其他内置程序的非关键字状态(Object、Math、NaN…),但您可能无法避免它们,而且实用代码通常不是在主动恶意环境中编写的,因此这不是担心未定义的好理由。(但如果您正在编写代码生成器,请随意使用void 0。)
随着变量如何发挥作用,是时候解决实际问题了:对象财产。没有理由对对象财产使用typeof。早期关于特征检测的例外在这里不适用–typeof只对变量有特殊行为,引用对象财产的表达式不是变量。
这:
if (typeof foo.bar === 'undefined') {
⋮
}
始终完全等于此³:
if (foo.bar === undefined) {
⋮
}
考虑到上面的建议,避免让读者混淆为什么要使用typeof,因为使用==来检查等式是最有意义的,因为稍后可以将其重构为检查变量的值,并且因为它看起来更简单,所以在这里也应该始终使用==undefined³。
当涉及到对象财产时,需要考虑的另一件事是您是否真的想检查未定义的属性。给定的属性名称可以在对象上不存在(读取时产生未定义的值),可以在对象本身上出现,但值未定义,可以在该对象的原型上出现,值未定义或出现在其中一个值未定义的对象上obj中的“key”将告诉您键是否位于对象原型链上的任何位置,而object.protype.hasOwnProperty.call(obj,“key”)将告诉您它是否直接位于对象上。不过,我不会在这个答案中详细讨论原型和使用对象作为字符串键映射,因为它主要是为了应对其他答案中的所有坏建议,而不管对原始问题的可能解释。阅读MDN上的对象原型了解更多信息!
¹不寻常的变量名称示例选择?这是Firefox的NoScript扩展中真正的死代码。²但是,不要认为不知道范围内的内容是可以的。滥用动态范围导致的奖金漏洞:项目零1225再次假设ES5+环境,undefined指的是全局对象的未定义属性。
其他回答
“if(window.x){}”是错误安全的
很可能您想要if(window.x)。即使x尚未声明(var x;),该检查也是安全的-浏览器不会抛出错误。
示例:我想知道我的浏览器是否支持历史API
if (window.history) {
history.call_some_function();
}
工作原理:
window是一个包含所有全局变量作为其成员的对象,尝试访问不存在的成员是合法的。如果x尚未声明或未设置,则window.x返回undefined。undefined在if()求值时导致false。
如果使用的是Angular:
angular.isUndefined(obj)
angular.isUndefined(obj.prop)
Undercore.js:
_.isUndefined(obj)
_.isUndefined(obj.prop)
我找到了这篇文章,《在JavaScript中处理未定义的7个技巧》,它展示了关于未定义的真正有趣的事情如:
undefined的存在是JavaScript的许可性质的结果,允许使用:
未初始化变量不存在的对象财产或方法访问数组元素的越界索引不返回任何内容的函数的调用结果
ECMAScript 10引入了一个新特性——可选链接,只有当对象定义为如下时,才可以使用该特性来使用对象的属性:
const userPhone = user?.contactDetails?.phone;
只有在定义了user和contactDetails时,它才会引用phone属性。
裁判。https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
如果你这样做
if (myvar == undefined )
{
alert('var does not exists or is not initialized');
}
当变量myvar不存在时,它将失败,因为没有定义myvar,所以脚本被破坏,测试没有效果。
由于窗口对象在函数外部具有全局作用域(默认对象),因此声明将“附加”到窗口对象。
例如:
var myvar = 'test';
全局变量myvar与window.myvar或window['myvar']相同
为了避免在存在全局变量时要测试的错误,最好使用:
if(window.myvar == undefined )
{
alert('var does not exists or is not initialized');
}
一个变量是否真的存在并不重要,它的值是不正确的。否则,用undefined初始化变量是愚蠢的,最好使用值false来初始化。当你知道你声明的所有变量都是用false初始化的时候,你可以简单地检查它的类型或者依赖它!window.myvar检查它是否具有正确/有效的值。因此,即使没有定义变量!window.myvar对于myvar=undefined或myvar=false或myvar=0是相同的。
如果需要特定类型,请测试变量的类型。要加快测试条件,您最好执行以下操作:
if( !window.myvar || typeof window.myvar != 'string' )
{
alert('var does not exists or is not type of string');
}
当第一个简单条件为真时,解释器将跳过下一个测试。
最好使用变量的实例/对象来检查它是否获得了有效值。它更稳定,是一种更好的编程方式。
(y)