在我看来,有四种不同的方法可以确定给定对象(例如foo)是否具有定义的给定属性(例如bar):
if (foo.hasOwnProperty(bar)) {if ('bar' in foo) {if (typeof foo.bar !== 'undefined') {if (foo.bar === undefined) {
要确定对象中是否存在名为“ bar”的属性foo,这三个语句是否都等效?是否有任何我不知道的微妙语义使这三个语句中的任何一个都不同?
在我看来,有四种不同的方法可以确定给定对象(例如foo)是否具有定义的给定属性(例如bar):
if (foo.hasOwnProperty(bar)) {if ('bar' in foo) {if (typeof foo.bar !== 'undefined') {if (foo.bar === undefined) {要确定对象中是否存在名为“ bar”的属性foo,这三个语句是否都等效?是否有任何我不知道的微妙语义使这三个语句中的任何一个都不同?
不,它们完全不同。例子:
foo = {bar: undefined};
Object.prototype.baz = undefined;
Object.prototype.bing = "hello";
然后:
(typeof foo.bar != "undefined") === false
('bar' in foo) === true
(foo.hasOwnProperty('bar')) === true
(typeof foo.baz != "undefined") === false
('baz' in foo) === true
(foo.hasOwnProperty('baz')) === false
(typeof foo.bing != "undefined") === true
('bing' in foo) === true
(foo.hasOwnProperty('bing')) === false
逻辑方面:
foo.hasOwnProperty('bar')暗示'bar' in footypeof foo.bar != "undefined"暗示'bar' in foo这些都是不同的:
foo.hasOwnProperty('bar')告诉你是否foo有属性并且不沿着原型链进行查找。
'bar' in foo检查原型链,当它bar在链中的任何对象中找到属性时返回 true。
typeof foo.bar != 'undefined'foo如果原型链上的任何对象具有属性bar并且其值为 not ,则返回 true undefined。
这是一个演示这些差异的示例:
var foo1 = { 'bar1': 10, 'bar2': undefined };
function ctor() {}
ctor.prototype = foo1;
var foo2 = new ctor();
foo2.bar3 = 20;
console.log(foo2.hasOwnProperty('bar1')); // false
console.log(foo2.hasOwnProperty('bar2')); // false
console.log(foo2.hasOwnProperty('bar3')); // true
console.log(foo2.hasOwnProperty('bar4')); // false
console.log('bar1' in foo2); // true
console.log('bar2' in foo2); // true
console.log('bar3' in foo2); // true
console.log('bar4' in foo2); // false
console.log(typeof foo2.bar1 != 'undefined'); // true
console.log(typeof foo2.bar2 != 'undefined'); // false
console.log(typeof foo2.bar3 != 'undefined'); // true
console.log(typeof foo2.bar4 != 'undefined'); // false
一个区别是,方法 1 将仅检查 foo 对象的属性栏,而最后两个方法还将检查原型的继承属性。
'bar' in foo
将查找原型链的任何位置。如果 foo.bar!==位于的原型链中的任何位置,测试是否undefined也会返回 true ,但请记住,如果 bar定义在 foo 上,并设置为undefined,这将返回 false。barfoo
hasOwnProperty更加挑剔 - 它只会返回 truebar被定义为foo.
每个 MDN
从 Object 继承的每个对象都继承了 hasOwnProperty 方法。该方法可用于判断一个对象是否具有指定属性作为该对象的直接属性;与 in 运算符不同,此方法不检查对象的原型链。
各种方法/关键字之间确实存在一些细微的差异。
foo.hasOwnProperty('bar')只有在 foo 对象本身上定义了属性 'bar' 时才返回 true。然而,其他属性,例如 'toString' 将返回 false,因为它们是在原型链中定义的。
如果指定的in属性在指定的对象中,则关键字运算符返回 true。两者都'bar' in foo将'toString' in foo返回 true。
由于您正在检查属性的状态,因此当 bar 未在 foo 上定义以及 bar 已定义但值设置为 时,结果将为真undefined。
为了补充其他人所说的,如果您只是想知道一个属性是否存在并且具有非错误值(不是undefined, null, false, 0, "", NaN, 等...),您可以这样做:
if (foo.bar) {
// code here
}
只要您对特定情况下的错误值不感兴趣,此快捷方式就会告诉您该变量是否已设置为对您有用的东西。
如果您想知道该属性是否以任何方式存在于对象上,我发现这是最有用、最简短、最易读的:
if ('bar' in foo) {
// code here
}
也可以在函数参数上使用类似的东西(同样只要你不关心虚假值):
function foo(bar) {
if (bar) {
// bar was passed and has some non-falsey value
}
}