JavaScript:成员是否已定义?

20

我认为有四种不同的方法可以确定给定对象(例如foo)是否定义了给定属性(例如bar):

  1. if (foo.hasOwnProperty(bar)) {
  2. if ('bar' in foo) {
  3. if (typeof foo.bar !== 'undefined') {
  4. if (foo.bar === undefined) {

要确定对象foo中是否存在名为“bar”的属性,这三个语句都是等效的吗?是否存在我不知道的微妙语义使得这些语句中的任何一个与其他语句不同?


1
值得注意的是,除非有人覆盖了全局的 undefined 变量,否则也可以将 3 写成 if (foo.bar !== undefined) { - Domenic
6个回答

17
不,它们完全不同。例如:
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 foo
  • typeof foo.bar != "undefined" 意味着 'bar' in foo
  • 但这些是你可以得出的唯一推论;就像上面的反例所示,没有其他普遍真实的含义。

1
+1 - 我忘记考虑bar可能在foo上,但被设置为未定义。 - Adam Rackis

10

它们都是不同的:

  1. foo.hasOwnProperty('bar') 可以告诉你 foo 是否有这个属性,但不查找原型链。

  2. 'bar' in foo 检查原型链,并返回true,当它在链中的任何对象中找到属性 bar 时。

  3. typeof foo.bar != 'undefined' 返回true,如果 foo 或其原型链中的任何对象具有属性 bar 并且其值不是 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

2

一个不同之处在于,方法1仅检查属性“bar”的foo对象,而后两种方法还将检查原型以获取继承属性。


2
'bar' in foo 

在原型链上的任何地方都可以查找。测试 foo.bar !== undefined,如果 barfoo 的原型链上的任何位置,也会返回 true,但请记住,如果 bar 已经在 foo 上定义,并且设置为 undefined,则此方法将返回 false。

hasOwnProperty 更加挑剔 - 它只有在 bar 作为 foo 的直接属性被定义时才会返回 true。

根据 MDN

从 Object 继承的每个对象都继承了 hasOwnProperty 方法。该方法可用于确定对象是否具有指定属性作为该对象的直接属性;与 in 运算符不同,此方法不检查对象的原型链。


2

各种方法/关键字之间确实存在一些微妙的差异。

  1. foo.hasOwnProperty('bar')仅在foo对象本身上定义了属性'bar'时返回true。但是,其他属性(例如'toString')将返回false,因为它们定义在原型链上。

  2. 关键字操作符in如果指定的属性在指定的对象中,则返回true。 'bar' in foo'toString' in foo都会返回true。

  3. 由于您正在检查属性的状态,因此当foo上未定义bar并且bar已定义但值设置为undefined时,结果将为true。


0
补充其他人所说的,如果你只想知道一个属性是否存在并且具有非假值(不是undefinednullfalse0""NaN等),你可以这样做:
if (foo.bar) {
     // code here
}

只要在您的特定情况下不关心 falsey 值,这个快捷方式将告诉您变量是否已经设置为对您有用的内容。
如果您想知道对象上是否以任何方式存在该属性,我认为这是最有用、简洁和易读的方法:
if ('bar' in foo) {
    // code here
}

如果您不关心假值,也可以在函数参数上使用类似的方法:

function foo(bar) {
    if (bar) {
        // bar was passed and has some non-falsey value
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接