20

拿这个片段,

var a = {

}

if(typeof a.c === 'undefined'){
 console.log('inside if');
}
if(a.c === undefined){
 console.log('inside if');
}

两者都if导致true. 特定于某些浏览器的这两种语句有什么区别吗?

此外,在我的上一个项目中,我已经typeof a.c == 'undefined'多次使用过检查json数据中的值。

现在,我知道这不是好方法,因为某些价值也可能undefined如此,所以我的逻辑将失败。

我应该使用hasOwnProperty.

但我确信没有任何价值undefined,我可以用typeof a.c == 'undefined'它来代替hasOwnProperty还是应该typeofhasOwnProperty

4

3 回答 3

31

更新:你可能想看看这个问题:variable === undefined vs. typeof variable === "undefined")。

非常旧的浏览器(Netscape 2、IIRC 和可能的 IE 4 或更低版本)中,您无法将值与 进行比较undefined,因为这会导致错误。然而,在任何(半)现代浏览器中,没有理由检查typeof value === 'undefined'而不是value === undefined(除了有人可能重新定义了变量的偏执狂undefined)。

hasOwnProperty服务于不同的目的。它检查对象是否具有给定名称的属性,而不是它的原型;即不管继承的属性。如果你想检查一个对象是否包含某个属性,继承与否,你应该使用if ('c' in a) {...

但基本上,这些可能都会起作用:

if (a.c === undefined) console.log('No c in a!');
if (typeof a.c === 'undefined') console.log('No c in a!');
if (!('c' in a)) console.log('No c in a!');
if (!a.hasOwnProperty('c')) console.log('No c in a!');

主要区别在于:

  • a.c === undefined如果有人做过undefined = 'defined'或一些类似的伎俩,会产生意想不到的结果;
  • !('c' in a)不是很可读(恕我直言)
  • !a.hasOwnProperty('c')false如果对象a不包含属性,将返回c,但它的原型包含。

就个人而言,我更喜欢第一个,因为它更具可读性。如果您偏执并希望避免重新定义的风险undefined,请将您的代码包装在一个自动执行的匿名函数中,如下所示:

(function (undefined) {
  // in here, 'undefined' is guaranteed to be undefined. :-)

  var a = {

  };

})();
于 2012-06-05T10:14:03.103 回答
3

如果您检查作为解析 JSON 字符串结果的标准对象,.hasOwnProperty则没有明显的好处。当然,除非你或你正在使用的某个库一直在搞乱Object.prototype.

一般来说,undefined这样可以重新定义,但我自己没有遇到过 - 我也不认为我会这样做。但是,(AFAIK)不可能弄乱typeof. 在这方面,后者是最安全的方法。我确实相信一些古老的浏览器也不能很好地使用该undefined关键字。

在恢复中:无需去更换每张typeof支票。就个人而言:不过,我认为养成使用 . 的习惯是一种好习惯.hasOwnProperty。因此,我建议,如果某个属性可能存在但未定义,.hasOwnPorperty这是最安全的选择。


回应您的评论:是的,typeof大约 95% 的时间会满足您的需求。.hasOwnProperty将工作 99% 的时间。但是,正如名称所示:不会检查继承链更高的属性,请考虑以下示例:

Child.prototype = new Parent();
Child.prototype.constructor=Child;//otherwise instance.constructor points to parent

function Parent()
{
    this.foo = 'bar';
}

function Child()
{
    this.bar = 'baz';
}

var kiddo = new Child();
if (kiddo.hasOwnProperty('foo'))
{
    console.log('This code won\'t be executed');
}
if (typeof kiddo.foo !== 'undefined')
{
    console.log('This will, foo is a property of Parent');
}

因此,如果您想检查单个对象是否具有属性,hasOwnProperty这就是您所需要的。特别是如果您要更改该属性的值(如果它是原型属性,则可以更改所有实例)。
如果您想知道一个属性是否有值(除 之外undefined),无论它位于继承链中的哪个位置,您都需要typeof. 我在某处有一个递归函数来确定可以在继承链中找到该属性的位置。一旦我找到它,我也会在这里发布它。

更新:

正如所承诺的,在继承链中定位属性的功能。这不是我不久前使用的实际功能,所以我整理了一份工作草案。它并不完美,但它可以很好地帮助您:

function locateProperty(obj,prop,recursion)
{
    recursion = recursion || false;
    var current = obj.constructor.toString().match(/function\s+(.+?)\s*\(/m)[1];
    if (!(obj.hasOwnProperty(prop)))
    {
        if (current === 'Function' || recursion === current)
        {
            return false;
        }
        return locateProperty(new window[current](),prop,current);
    }
    return current;
}
//using the object kiddo
locateProperty(kiddo,'foo');//returns 'Parent'
locateProperty(kiddo,'bar');//returns 'Parent', too

为避免最后一个故障,您可以将最后一个return current;语句替换为return obj;. 或者,更好的是,将以下行添加到上面的代码段中:

Child.prototype.constructor=Child;

我在第一次编辑时忘记了...

于 2012-06-05T10:22:07.523 回答
0
  • 将 p 的可枚举属性复制到 o,并返回 o。

  • 如果 o 和 p 具有同名的属性,则不保留 o 的属性。

  • 此函数不处理 getter 和 setter 或复制属性。

    function merge(o, p) 
    {
        for(prop in p) 
        {   
            // For all props in p.
            if (o.hasOwnProperty[prop]) continue;  // Except those already in o.
            o[prop] = p[prop];                     // Add the property to o.
        }
    
        return o;
    }
    

o.hasOwnProperty[prop]和 和有什么不一样o.hasOwnProperty(prop)

于 2012-06-16T16:32:05.063 回答