开发者问题收集

检测未定义的对象属性

2008-08-26
1503751

如何检查 JavaScript 中的对象属性是否未定义?

3个回答

检查属性值是否为特殊值 undefined 的常用方法是:

if(o.myProperty === undefined) {
  alert("myProperty value is the special value `undefined`");
}

检查对象是否实际上没有这样的属性,因此在尝试访问它时默认返回 undefined

if(!o.hasOwnProperty('myProperty')) {
  alert("myProperty does not exist");
}

检查与标识符关联的值是否为特殊值 undefined 或者 该标识符是否尚未声明:

if(typeof myVariable === 'undefined') {
  alert('myVariable is either the special value `undefined`, or it has not been declared');
}

注意:最后一种方法是引用 未声明 标识符而不会出现早期错误的唯一方法,这与具有 undefined 值不同。

在 ECMAScript 5 之前的 JavaScript 版本中,全局对象上名为“undefined”的属性是可写的,因此只需简单检查 foo ===如果意外重新定义,undefined 可能会出现意外行为。在现代 JavaScript 中,该属性是只读的。

但是,在现代 JavaScript 中,“undefined”不是关键字,因此函数内的变量可以命名为“undefined”并遮蔽全局属性。

如果您担心这种(不太可能的)极端情况,可以使用 void 运算符 获取特殊的 undefined 值本身:

if(myVariable === void 0) {
  alert("myVariable is the special value `undefined`");
}
2009-01-06

我认为这个主题有很多错误的答案。与普遍看法相反,“undefined” 不是 JavaScript 中的关键字,实际上可以为其分配值。

正确代码

执行此测试的最可靠方法是:

if (typeof myVar === "undefined")

这将始终返回正确的结果,甚至可以处理未声明 myVar 的情况。

退化代码。请勿使用。

var undefined = false;  // Shockingly, this is completely legal!
if (myVar === undefined) {
    alert("You have been misled. Run away!");
}

此外, myVar === undefined 将在未声明 myVar 的情况下引发错误。

MarkPflug
2010-08-23

这里的许多答案都极力推荐 typeof ,但 typeof 是一个糟糕的选择 。它 永远 不应用于检查变量是否具有值 undefined ,因为它充当了对值 undefined 和变量是否存在的综合检查。在绝大多数情况下,您知道变量何时存在,如果您在变量名称或字符串文字 '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) {
    ⋮
}

关于此的一些常见误解包括:

  • 读取“未初始化”的变量( var foo )或参数( function bar(foo) { … },称为 bar() )将失败。这根本不是真的——没有显式初始化的变量和未赋值的参数始终变为 undefined ,并且始终在范围内。

  • 可以覆盖 undefined 。确实 undefined 不是关键字,但它 只读且不可配置的。尽管其他内置函数不是关键字状态( ObjectMathNaN ……),但您可能不会避免使用这些内置函数,并且实际代码通常不是在主动恶意环境中编写的,因此这不是担心 undefined 的好理由。 (但如果您正在编写代码生成器,请随意使用 void 0 。)

了解了变量的工作方式后,是时候解决实际问题了:对象属性。没有理由对对象属性使用 typeof 。先前关于特性检测的例外不适用于此处 - typeof 仅对变量具有特殊行为,引用对象属性的表达式不是变量。

这个:

if (typeof foo.bar === 'undefined') {
    ⋮
}

始终 与这个³:

if (foo.bar === undefined) {
    ⋮
}

完全等同于

if (foo.bar === undefined) {
    ⋮
}

并且考虑到上述建议,为了避免使读者对您使用 typeof 的原因感到困惑,因为使用 === 检查相等性是最有意义的,因为它可以重构为稍后检查变量的值,并且因为它看起来更好, 您也应该始终在这里使用 === undefined ³

当涉及到对象属性时,还需要考虑的另一件事是您是否真的想要检查 undefined 。给定的属性名称可以不存在于对象上(读取时生成值 undefined ),可以存在于对象本身上,值为 undefined ,可以存在于对象的原型上,值为 undefined ,或者存在于上述任一对象上,但值为非 undefined'key' in obj 将告诉您键是否位于对象原型链的任何位置,而 Object.prototype.hasOwnProperty.call(obj, 'key') 将告诉您它是否直接位于对象上。不过,在这个答案中,我不会详细介绍原型和使用对象作为字符串键映射,因为这主要是为了反驳其他答案中的所有错误建议,而不管原始问题的可能解释如何。阅读 MDN 上的对象原型 以了解更多信息!

¹示例变量名称的不寻常选择?这是Firefox的NoScript扩展的真实死亡代码。
²不认为不知道范围中的内容一般是可以的。滥用动态范围引起的奖励脆弱性: 项目零1225
再次假设ES5+环境,该 undefined 是指全局对象的 不确定的 属性。

Ry-
2014-02-26