检查 JavaScript 中的对象属性是否未定义的最佳方法是什么?
检测未定义的对象属性
检查属性值是否为特殊值的常用方法undefined
是:
if(o.myProperty === undefined) {
alert("myProperty value is the special value `undefined`");
}
要检查对象是否实际上没有这样的属性,因此undefined
在您尝试访问它时默认会返回:
if(!o.hasOwnProperty('myProperty')) {
alert("myProperty does not exist");
}
检查与标识符关联的值是否是特殊值undefined
,或者该标识符是否尚未声明。注意:此方法是引用未声明的(注意:不同于具有 值undefined
)标识符而没有早期错误的唯一方法:
if(typeof myVariable === 'undefined') {
alert('myVariable is either the special value `undefined`, or it has not been declared');
}
在 ECMAScript 5 之前的 JavaScript 版本中,全局对象上名为“undefined”的属性是可写的,因此foo === undefined
如果意外地重新定义了简单的检查,可能会出现意外的行为。在现代 JavaScript 中,该属性是只读的。
但是,在现代 JavaScript 中,“undefined”不是关键字,因此函数内的变量可以命名为“undefined”并隐藏全局属性。
如果您担心这种(不太可能的)边缘情况,您可以使用void 运算符来获取特殊undefined
值本身:
if(myVariable === void 0) {
alert("myVariable is the special value `undefined`");
}
我相信这个话题有很多不正确的答案。与普遍看法相反,“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 的情况下会引发错误。
尽管这里有许多其他答案强烈推荐,但这typeof
是一个糟糕的选择。它永远不应该用于检查变量是否具有值undefined
,因为它作为对值undefined
和变量是否存在的组合检查。在绝大多数情况下,您知道变量何时存在,并且typeof
如果您在变量名称或字符串字面量中打错字,只会引入潜在的静默失败'undefined'
。
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) { … }
,称为 asbar()
) 将失败。这根本不是真的——没有显式初始化的变量和没有给定值的参数总是变成undefined
,并且总是在范围内。这
undefined
可以被覆盖。这确实undefined
不是关键字,但它是只读且不可配置的。还有其他内置程序,尽管它们处于非关键字状态(Object
,Math
,NaN
...),但您可能不会避免,而且实用代码通常不是在恶意的环境中编写的,因此这不是担心 的好理由undefined
。(但如果您正在编写代码生成器,请随意使用void 0
。)
随着变量如何工作,是时候解决实际问题了:对象属性。没有理由使用typeof
对象属性。早期关于特征检测的例外不适用于这里——typeof
仅对变量有特殊行为,引用对象属性的表达式不是变量。
这个:
if (typeof foo.bar === 'undefined') {
⋮
}
是始终完全等同于this³:
if (foo.bar === undefined) {
⋮
}
并考虑到上面的建议,以避免让读者混淆你为什么使用typeof
,因为使用它===
来检查相等性最有意义,因为它可以重构为稍后检查变量的值,并且因为它只是简单的看起来更好,你也应该=== undefined
在这里使用³。
涉及对象属性时要考虑的另一件事是您是否真的想要检查undefined
。给定的属性名称可以不存在于对象上(undefined
读取时产生值),以 value出现在对象本身上,以 valueundefined
出现在对象的原型上undefined
,或出现在具有非undefined
值的任何一个上。'key' in obj
会告诉你一个键是否在对象原型链上的任何地方,并Object.prototype.hasOwnProperty.call(obj, 'key')
会告诉你它是否直接在对象上。不过,我不会在这个关于原型和使用对象作为字符串键映射的答案中详细介绍,因为它主要是为了反驳其他答案中的所有错误建议,而不管原始问题的可能解释如何。继续阅读MDN 上的对象原型了解更多!
¹ 不寻常的示例变量名称选择?这是来自 Firefox 的 NoScript 扩展的真正死代码。
² 不过,不要假设不知道范围内的内容通常是可以的。滥用动态范围导致的额外漏洞:Project Zero 1225³
再次假设 ES5+ 环境并undefined
引用undefined
全局对象的属性。
在 JavaScript 中有null和undefined。它们有不同的含义。
- undefined表示变量值尚未定义;不知道它的value是什么。
- null表示变量值已定义并设置为 null(没有值)。
Marijn Haverbeke 在他的免费在线书籍“ Eloquent JavaScript ”(重点是我的)中说:
还有一个类似的值,null,它的意思是'这个值被定义了,但是它没有一个值'。undefined 和 null 之间的含义差异主要是学术性的,通常不是很有趣。在实际程序中,经常需要检查某些东西是否“有value”。在这些情况下,可以使用表达式 something == undefined,因为即使它们不是完全相同的值,null == undefined 也会产生 true。
因此,我想检查某些内容是否未定义的最佳方法是:
if (something == undefined)
对象属性应该以相同的方式工作。
var person = {
name: "John",
age: 28,
sex: "male"
};
alert(person.name); // "John"
alert(person.fakeVariable); // undefined
这是什么意思:“未定义的对象属性”?
实际上,它可能意味着两个完全不同的事情!首先,它可以表示从未在对象中定义的属性,其次,它可以表示具有未定义值的属性。让我们看看这段代码:
var o = { a: undefined }
是o.a
未定义?是的!它的值是未定义的。是o.b
未定义?当然!根本没有属性“b”!好的,现在看看不同方法在两种情况下的表现:
typeof o.a == 'undefined' // true
typeof o.b == 'undefined' // true
o.a === undefined // true
o.b === undefined // true
'a' in o // true
'b' in o // false
我们可以清楚地看到,typeof obj.prop == 'undefined'
和obj.prop === undefined
是等价的,它们不区分那些不同的情况。并且'prop' in obj
可以检测到一个属性根本没有定义的情况,并且不关注可能未定义的属性值。
那么该怎么办?
1) 您想知道某个属性是否未通过第一个或第二个含义定义(最典型的情况)。
obj.prop === undefined // IMHO, see "final fight" below
2)您只想知道对象是否具有某些属性而不关心它的value。
'prop' in obj
笔记:
- 您不能同时检查一个对象及其属性。例如,如果 x 未定义,则 this
x.a === undefined
或 thistypeof x.a == 'undefined'
会引发ReferenceError: x is not defined
。 - 变量
undefined
是一个全局变量(所以实际上它window.undefined
在浏览器中)。从 ECMAScript 1st Edition 开始就支持它,从 ECMAScript 5 开始它是只读的。因此,在现代浏览器中,它不能被重新定义为 true,因为许多作者喜欢用它来吓唬我们,但这对于旧浏览器来说仍然是正确的。
决战:obj.prop === undefined
vstypeof obj.prop == 'undefined'
优点obj.prop === undefined
:
- 它有点短,看起来有点漂亮
- 如果您拼写错误,JavaScript 引擎会给您一个错误
undefined
的缺点obj.prop === undefined
:
undefined
可以在旧浏览器中覆盖
优点typeof obj.prop == 'undefined'
:
- 真的是万能的!它适用于新旧浏览器。
的缺点typeof obj.prop == 'undefined'
:
'undefned'
(拼写错误)这里只是一个字符串常量,因此如果您像我刚才那样拼写错误,JavaScript 引擎将无法帮助您。
更新(对于服务器端 JavaScript):
Node.js 支持全局变量undefined
as global.undefined
(它也可以在没有 'global' 前缀的情况下使用)。我不知道服务器端 JavaScript 的其他实现。