【问题标题】:Undefined, typeof undefined, hasOwnProperty未定义,未定义类型,hasOwnProperty
【发布时间】:2018-04-12 21:58:00
【问题描述】:

拿着这个sn-p,

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 还是应该将我所有的 typeof 更改为 hasOwnProperty

【问题讨论】:

标签: javascript


【解决方案1】:

更新:您可能想看看这个问题: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!');

主要区别在于:

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

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

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

  var a = {

  };

})();

【讨论】:

  • 在今天的 Chrome 版本中,foo === undefined 会触发错误。看到这个答案:stackoverflow.com/a/4725697/851498
  • 另外,对于“偏执狂”,这就是为什么很多人使用以下技巧的原因:( function( window, document, undefined ) { /* your code */ }( window, document ) ); :-) 哦,你刚刚编辑添加了这个。
  • @FlorianMargaine:啊,foo === undefined 是一个很好的。不过,使用value === undefined 是一个更有说服力的论据,因为它允许您找到未声明的变量,这是非常糟糕的事情™。
  • 虽然它们会导致错误,这可能不是一件好事™ :-)
  • @Jashwant:没错,好点!在a.c = undefined 之后,!('c' in a) 将返回 false,但 a.c === undefined 将返回 truetypeof a.c === 'undefined' 也将返回。
【解决方案2】:

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

一般来说,undefined 可以重新定义,但我自己没有遇到过这种情况——我想我也不会这样做。然而,混淆typeof 的返回值是不可能的(AFAIK)。在这方面,后者是最安全的方法。我确实相信一些古老的浏览器也不能很好地使用 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;。或者,更好的是,将以下行添加到上面的 sn-p:

Child.prototype.constructor=Child;

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

【讨论】:

  • 所以,我不应该更改我的代码,但为了将来,我应该使用 hasOwnProperty 。对吧?
  • 编辑了我的答案,以提供有关您的评论的更多信息。
【解决方案3】:
  • 将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) 有什么区别?

【讨论】:

    猜你喜欢
    • 2020-09-21
    • 1970-01-01
    • 1970-01-01
    • 2022-12-23
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 2016-07-05
    相关资源
    最近更新 更多