未定义,typeof undefined,hasOwnProperty

时间:2012-06-05 10:03:53

标签: javascript

拿这个片段,

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,还是应该使用{{1}更改typeof hasOwnProperty }

3 个答案:

答案 0 :(得分:26)

更新:您可能想查看此问题: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 = {

  };

})();

答案 1 :(得分:3)

如果检查标准对象是解析JSON字符串的结果,.hasOwnProperty没有明显的好处。当然,除非你正在使用的某个或某些lib已经在使用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;

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

答案 2 :(得分: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)之间的区别是什么?