如何检查对象在JavaScript中是否具有特定属性?

考虑:

x = {'key': 1};
if ( x.hasOwnProperty('key') ) {
    //Do this
}

这是最好的方法吗?


当前回答

对于测试简单对象,请使用:

if (obj[x] !== undefined)

如果您不知道它是什么对象类型,请使用:

if (obj.hasOwnProperty(x))

所有其他选项都较慢。。。

细节

对Node.js下100000000个周期的性能评估,其他人在这里建议了五个选项:

function hasKey1(k,o) { return (x in obj); }
function hasKey2(k,o) { return (obj[x]); }
function hasKey3(k,o) { return (obj[x] !== undefined); }
function hasKey4(k,o) { return (typeof(obj[x]) !== 'undefined'); }
function hasKey5(k,o) { return (obj.hasOwnProperty(x)); }

评估告诉我们,除非我们特别想检查对象的原型链以及对象本身,否则不应使用通用形式:

if (X in Obj)...

根据使用情况,速度慢2到6倍

hasKey1 execution time: 4.51 s
hasKey2 execution time: 0.90 s
hasKey3 execution time: 0.76 s
hasKey4 execution time: 0.93 s
hasKey5 execution time: 2.15 s

总之,如果您的Obj不一定是一个简单的对象,并且您希望避免检查对象的原型链,并确保x由Obj直接拥有,请使用if(Obj.hasOwnProperty(x))。。。。

否则,当使用简单对象而不担心对象的原型链时,使用if(typeof(obj[x])!=='undefined')。。。是最安全、最快的方式。

如果你使用一个简单的对象作为哈希表,并且从不做任何奇怪的事情,我会使用If(obj[x])。。。因为我觉得它更可读。

其他回答

让我们在这里消除一些困惑。首先,让我们通过假设hasOwnProperty已经存在来简化;目前使用的绝大多数浏览器都是如此。

如果传递给它的属性名已添加到对象中,hasOwnProperty返回true。它完全独立于分配给它的实际值,而实际值可能完全未定义。

因此:

var o = {}
o.x = undefined

var a = o.hasOwnProperty('x')  // a is true
var b = o.x === undefined // b is also true

然而:

var o = {}

var a = o.hasOwnProperty('x')  // a is now false
var b = o.x === undefined // b is still true

问题是当原型链中的对象具有值为undefined的属性时会发生什么?hasOwnProperty将为false,也将为false!==未定义。然而,对于。。中仍将在枚举中列出它。

最重要的是,没有跨浏览器的方法(因为Internet Explorer不公开__prototype__)来确定特定标识符是否未附加到对象或其原型链中的任何内容。

if(x.hasOwnProperty("key")){
  // …
}

因为

if(x.key){
  // …
}

如果x.key错误(例如,x.key==“”),则失败。

迭代对象自身财产的更好方法:

如果要在不使用hasOwnProperty()检查的情况下迭代对象的财产,用于(let key of Object.keys(stud)){}方法:

for(let key of Object.keys(stud)){
  console.log(key); // will only log object's Own properties
}

完整示例并与hasOwnProperty()中的for进行比较

function Student() {
  this.name = "nitin";
}

Student.prototype = {
  grade: 'A'
}

let stud = new Student();

// for-in approach
for(let key in stud){
  if(stud.hasOwnProperty(key)){
    console.log(key); // only outputs "name"
  }
} 

//Object.keys() approach
for(let key of Object.keys(stud)){
  console.log(key);
}

也可以使用ES6 Reflect对象:

x = {'key': 1};
Reflect.has( x, 'key'); // returns true

Reflect.has的MDN文档可在此处找到。

静态Reflect.has()方法的工作方式类似于函数中的in运算符。

2022年更新

Object.hasOwn()

建议使用Object.hasOwn()而不是Object.hasOwnerProperty(),因为它适用于使用Object.create(null)创建的对象以及已重写继承的hasOwnProperty()方法的对象。虽然可以通过对外部对象调用Object.pr原型.hasOwnProperty()来解决这些问题,但Object.hasOwn()更直观。

实例

const object1 = {
  prop: 'exists'
};

console.log(Object.hasOwn(object1, 'prop'));
// expected output: true

原答覆

我真的被给出的答案弄糊涂了——大多数答案都是完全错误的。当然,您可以拥有具有未定义、null或false值的对象财产。因此,简单地将属性检查减少为this〔property〕的类型,或者更糟糕的是,x.key将给您带来完全误导的结果。

这取决于你要找什么。如果你想知道一个对象是否在物理上包含一个属性(并且它不是来自原型链上的某个地方),那么object.hasOwnProperty就是最好的方法。所有现代浏览器都支持它。(Safari 2.0.1和更早版本中缺少它,但这些版本的浏览器很少再使用了。)

如果您要查找的是一个对象上是否有可迭代的属性(当您迭代对象的财产时,它就会出现),那么在对象中执行:prop将获得您想要的效果。

由于使用hasOwnProperty可能是您想要的,并且考虑到您可能需要回退方法,我向您介绍了以下解决方案:

var obj = {
    a: undefined,
    b: null,
    c: false
};

// a, b, c all found
for ( var prop in obj ) {
    document.writeln( "Object1: " + prop );
}

function Class(){
    this.a = undefined;
    this.b = null;
    this.c = false;
}

Class.prototype = {
    a: undefined,
    b: true,
    c: true,
    d: true,
    e: true
};

var obj2 = new Class();

// a, b, c, d, e found
for ( var prop in obj2 ) {
    document.writeln( "Object2: " + prop );
}

function hasOwnProperty(obj, prop) {
    var proto = obj.__proto__ || obj.constructor.prototype;
    return (prop in obj) &&
        (!(prop in proto) || proto[prop] !== obj[prop]);
}

if ( Object.prototype.hasOwnProperty ) {
    var hasOwnProperty = function(obj, prop) {
        return obj.hasOwnProperty(prop);
    }
}

// a, b, c found in modern browsers
// b, c found in Safari 2.0.1 and older
for ( var prop in obj2 ) {
    if ( hasOwnProperty(obj2, prop) ) {
        document.writeln( "Object2 w/ hasOwn: " + prop );
    }
}

以上是hasOwnProperty()的一个有效的跨浏览器解决方案,但有一个警告:它无法区分原型和实例上相同属性的情况-它只是假设它来自原型。根据你的情况,你可以把它改得更宽或更严,但至少这应该更有帮助。