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

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

考虑:

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

这是最好的方法吗?

1248392 次浏览

是的,它是:)我认为你也可以做Object.prototype.hasOwnProperty.call(x, 'key'),如果x有一个名为hasOwnProperty的属性,它也应该工作:)

但这是测试自己的属性。如果你想检查它是否有一个可能是固有的属性,你可以使用typeof x.foo != 'undefined'

if (x.key !== undefined)

arminronacher似乎已经有了抢先一步,但是:

Object.prototype.hasOwnProperty = function(property) {return this[property] !== undefined;};
x = {'key': 1};
if (x.hasOwnProperty('key')) {alert('have key!');}
if (!x.hasOwnProperty('bar')) {alert('no bar!');}

一个更安全但更慢的解决方案,康拉德·鲁道夫35568">如指出乘康拉德·鲁道夫arminronacher将是:

Object.prototype.hasOwnProperty = function(property) {return typeof this[property] !== 'undefined';};

好吧,看起来我有正确的答案,除非你不想要继承的属性:

if (x.hasOwnProperty('key'))

以下是一些包含继承属性的其他选项:

if (x.key) // Quick and dirty, but it does the same thing as below.
if (x.key !== undefined)
if(x.hasOwnProperty("key")){// …}

因为

if(x.key){// …}

如果x.key为false sy则失败(例如,x.key === "")。

说明:由于严格模式,下面的内容现在基本上已经过时了,hasOwnProperty。正确的解决方案是使用严格模式并使用obj.hasOwnProperty检查属性的存在。这个答案早于这两件事,至少是广泛实现的(是的,它是那么老)。把以下作为历史笔记。


请记住,如果您不使用严格模式,undefined(不幸的是)没有是JavaScript中的保留字。因此,某人(显然是其他人)可能会有重新定义它的宏伟想法,破坏您的代码。

因此,更稳健的方法如下:

if (typeof(x.attribute) !== 'undefined')

另一方面,这种方法更冗长,也更慢。:-/

一个常见的替代方法是确保undefined实际上未定义的,例如将代码放入一个接受名为undefined的附加参数但未传递值的函数中。为确保它未传递值,您可以立即自己调用它,例如:

(function (undefined) {… your code …if (x.attribute !== undefined)… mode code …})();

2022更新

Object.hasOwn()

建议使用Object.hasOwn()而不是Object.hasOwnProperty(),因为它适用于使用Object.create(null)创建的对象以及覆盖了继承的hasOwnProperty()方法的对象。虽然可以通过在外部对象上调用Object.prototype.hasOwnProperty()来解决这些问题,但Object.hasOwn()更直观。

示例

const object1 = {prop: 'exists'};
console.log(Object.hasOwn(object1, 'prop'));// expected output: true

原答复

我真的被给出的答案弄糊涂了——其中大多数都是完全不正确的。当然,你可以有具有未定义、null或false值的对象属性。所以简单地将属性检查减少到typeof this[property],或者更糟糕的是,x.key会给你完全误导的结果。

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

如果您要查找的是对象上是否有可迭代的属性(当您迭代对象的属性时,它会出现),那么执行:prop in object将为您提供所需的效果。

由于使用hasOwnProperty可能是您想要的,并且考虑到您可能想要一个回退方法,我向您提供以下解决方案:

var obj = {a: undefined,b: null,c: false};
// a, b, c all foundfor ( 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 foundfor ( 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 olderfor ( var prop in obj2 ) {if ( hasOwnProperty(obj2, prop) ) {document.writeln( "Object2 w/ hasOwn: " + prop );}}

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

首先,让我们通过假设hasOwnProperty已经存在来简化;绝大多数当前使用的浏览器都是如此。

如果传递给它的属性名称已添加到对象中,则hasOwnProperty返回true。它完全独立于分配给它的实际值,可能正好是undefined

因此:

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

但是:

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

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

底线是没有跨浏览器的方式(因为Internet Explorer没有公开__prototype__)来确定特定标识符没有附加到其原型链中的对象或任何东西。

对于Underscore.js或(甚至更好Lodash

_.has(x, 'key');

它调用Object.prototype.hasOwnProperty,但(a)更短,(b)使用“对hasOwnProperty的安全引用”(即即使hasOwnProperty被覆盖,它也有效)。

具体来说,Lodash将_.has定义为:

function has(object, key) {return object ? hasOwnProperty.call(object, key) : false;}// hasOwnProperty = Object.prototype.hasOwnProperty

用途:

var x = {'key': 1};
if ('key' in x) {console.log('has');}

如果您正在搜索属性,则“不”。您想要:

if ('prop' in obj) { }

一般来说,您不应该关心属性是否来自原型或对象。

但是,由于您在示例代码中使用了“key”,因此看起来您将对象视为哈希值,在这种情况下,您的答案将是有意义的。所有哈希键都将是对象中的属性,并且您避免了原型提供的额外属性。

John Resig的回答非常全面,但我觉得不清楚。尤其是在obj中何时使用“'prop'”。

考虑Javascript中的以下对象

const x = {key: 1};

您可以使用in运算符来检查对象上是否存在该属性:

console.log("key" in x);

您还可以使用for - in循环遍历对象的所有属性,然后检查特定属性:

for (const prop in x) {if (prop === "key") {//Do something}}

您必须考虑此对象属性是否可枚举,因为不可枚举属性不会显示在for-in循环中。此外,如果可枚举属性隐藏原型的不可枚举属性,它将不会显示在Internet Explorer 8及更早版本中。

如果您想要所有实例属性的列表,无论是否可枚举,您都可以使用

Object.getOwnPropertyNames(x);

这将返回一个对象上存在的所有属性的名称数组。

反思提供了可用于与Javascript对象交互的方法。静态Reflect.has()方法的工作方式类似于in运算符作为函数。

console.log(Reflect.has(x, 'key'));// expected output: true
console.log(Reflect.has(x, 'key2'));// expected output: false
console.log(Reflect.has(object1, 'toString'));// expected output: true

最后,您可以使用typeof运算符直接检查对象属性的数据类型:

if (typeof x.key === "undefined") {console.log("undefined");}

如果该属性在对象上不存在,它将返回未定义的字符串。否则,它将返回适当的属性类型。但是,请注意,这并不总是检查对象是否具有属性的有效方法,因为您可以将属性设置为未定义,在这种情况下,使用typeof x.key仍将返回true(即使键仍在对象中)。

类似地,您可以通过直接与undefined Javascript属性进行比较来检查属性是否存在

if (x.key === undefined) {console.log("undefined");}

这应该可以工作,除非key在x对象上专门设置为undefined

另一种相对简单的方法是使用#0。这返回一个array,这意味着您获得数组的所有特征。

var noInfo = {};var info = {something: 'data'};
Object.keys(noInfo).length //returns 0 or falseObject.keys(info).length //returns 1 or true

虽然我们处在一个浏览器支持很好的世界里。因为这个问题太老了,我想我会添加这个:从JavaScript v1.8.5开始使用是安全的。

hasOwnProperty"可用于确定对象是否具有指定属性作为该对象的直接属性;与in运算符不同,此方法不会检查对象的原型链。"

所以很可能,对于你的问题,你不想使用hasOwnProperty,它确定属性是否存在附加的直接指向物体本身,。

如果您想确定该属性是否存在于原型链中,您可能希望像这样使用它:

if (prop in object) { // Do something }

这是针对特定情况的另一种选择。:)

如果您想测试对象上的成员并想知道它是否已设置为以下内容以外的内容:

  • ''
  • 虚假
  • null
  • 未定义
  • 0…

然后您可以使用:

var foo = {};foo.bar = "Yes, this is a proper value!";if (!!foo.bar) {// member is set, do something}

您也可以使用ES6#0对象

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

可以在<强>这里中找到Reflect.has的MDN文档。

静态Reflect.has()方法作为函数的工作方式与在操作员类似。

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

if (obj[x] !== undefined)

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

if (obj.hasOwnProperty(x))

所有其他选项都较慢…

详情

100,000,000循环的性能评估Node.js其他人建议的五个选项:

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 shasKey2 execution time: 0.90 shasKey3 execution time: 0.76 shasKey4 execution time: 0.93 shasKey5 execution time: 2.15 s

最重要的是,如果你的Obj不一定是一个简单的对象,并且你希望避免检查对象的原型链并确保x直接归Obj所有,请使用if (obj.hasOwnProperty(x))...

否则,当使用一个简单的对象并且不担心对象的原型链时,使用if (typeof(obj[x]) !== 'undefined')...是最安全和最快的方法。

如果您使用一个简单的对象作为哈希表并且从不做任何古怪的事情,我会使用if (obj[x])...,因为我发现它更具可读性。

带有反射的ECMAScript 6解决方案。创建一个包装器,如下所示:

/**Gets an argument from array or object.The possible outcome:- If the key exists the value is returned.- If no key exists the default value is returned.- If no default value is specified an empty string is returned.@param obj    The object or array to be searched.@param key    The name of the property or key.@param defVal Optional default version of the command-line parameter [default ""]@return The default value in case of an error else the found parameter.*/function getSafeReflectArg( obj, key, defVal) {"use strict";var retVal = (typeof defVal === 'undefined' ? "" : defVal);if ( Reflect.has( obj, key) ) {return Reflect.get( obj, key);}return retVal;}  // getSafeReflectArg

您需要使用方法object.hasOwnProperty(property)。如果对象具有属性,则返回true,如果对象没有,则返回false。

对象上存在一个方法“hasOwnProperty”,但不建议直接调用此方法,因为有时对象可能为空或对象上存在某些属性,例如:{ hasOwnProperty: false }

更好的方法是:

// Goodvar obj = {"bar": "here bar desc"}console.log(Object.prototype.hasOwnProperty.call(obj, "bar"));
// Bestconst has = Object.prototype.hasOwnProperty; // Cache the lookup once, in module scope.console.log(has.call(obj, "bar"));

不要这样做object.hasOwnProperty(key))。这真的很糟糕,因为这些方法可能会被有关对象的属性所掩盖-考虑{ hasOwnProperty: false }-或者,该对象可能是一个空对象(Object.create(null))

最好的方法是Object.prototype.hasOwnProperty.call(object, key)或:

const has = Object.prototype.hasOwnProperty; // Cache the lookup once, in module scope.console.log(has.call(object, key));/* Or */import has from 'has'; // https://www.npmjs.com/package/hasconsole.log(has(object, key));

当你可以做的时候,不要把事情复杂化:

var isProperty =  (objectname.keyname || "") ? true : false;

对于大多数情况来说,这是简单明了的…

您可以使用以下方法-

var obj = {a:1}console.log('a' in obj)               // 1console.log(obj.hasOwnProperty('a'))  // 2console.log(Boolean(obj.a))         // 3

下列方法的分别如下─

  1. 在第一种和第三种方法中,我们不仅在对象中搜索,而且在它的原型链中搜索。如果对象没有属性,但属性存在于它的原型链中,它将给出true。

var obj = {a: 2,__proto__ : {b: 2}}
console.log('b' in obj)console.log(Boolean(obj.b))

  1. 第二种方法只检查它自己的属性。

var obj = {a: 2,__proto__ : {b: 2}}
console.log(obj.hasOwnProperty('b'))

  1. 第一个和第三个之间的区别是,如果有一个属性的值未定义,第三种方法将给出false,而第一种方法将给出true。

var obj = {b : undefined}
console.log(Boolean(obj.b))console.log('b' in obj);

JavaScript现在正在发展和成长,因为它现在有很好甚至有效的方法来检查它。

这里有一些简单的方法来检查对象具有特定属性

  1. 使用hasOwnProperty()
const hero = {name: 'Batman'};
hero.hasOwnProperty('name');     // => truehero.hasOwnProperty('realName'); // => false
  1. 使用关键字/运算符in
const hero = {name: 'Batman'};
'name' in hero;     // => true'realName' in hero; // => false
  1. undefined关键字比较
const hero = {name: 'Batman'};
hero.name;     // => 'Batman'hero.realName; // => undefined
// So consider thishero.realName == undefined // => true (which means property does not exists in object)hero.name == undefined // => false (which means that property exists in object)

有关更多信息,请查看这里

性能

今天2020.12.17我在Chromev87、Safariv13.1.2和Firefox v83上对MacO HighSierra 10.13.6进行测试,以获取所选解决方案。

搜索结果

我只比较解决方案A-F,因为它们为详细信息部分的片段中使用的所有大小写提供了有效的结果。对于所有浏览器

  • 基于in(A)的解决方案是快速或最快的
  • 如果key不存在,则解决方案(E)对于大型对象的chrome最快,对于小型数组的Firefox最快
  • 对于小数组,解决方案(F)最快(~>10倍于其他解决方案)
  • 解(D, E)非常快
  • 基于losashhas(B)的解决方案最慢

输入图片描述

详情

我执行4个测试用例:

  • 当对象有10个字段并且搜索到的键存在时-您可以运行它这里
  • 当对象有10个字段并且搜索的键不存在时-您可以运行它这里
  • 当对象有10000个字段并且搜索到的键存在时-您可以运行它这里
  • 当对象有10000个字段并且搜索到的键存在时-您可以运行它这里

下面的代码片段显示了解决方案之间的差异ABCDEFGHIJK

// SO https://stackoverflow.com/q/135448/860099

// src: https://stackoverflow.com/a/14664748/860099function A(x) {return 'key' in x}
// src: https://stackoverflow.com/a/11315692/860099function B(x) {return _.has(x, 'key')}
// src: https://stackoverflow.com/a/40266120/860099function C(x) {return Reflect.has( x, 'key')}
// src: https://stackoverflow.com/q/135448/860099function D(x) {return x.hasOwnProperty('key')}
// src: https://stackoverflow.com/a/11315692/860099function E(x) {return Object.prototype.hasOwnProperty.call(x, 'key')}
// src: https://stackoverflow.com/a/136411/860099function F(x) {function hasOwnProperty(obj, prop) {var proto = obj.__proto__ || obj.constructor.prototype;return (prop in obj) &&(!(prop in proto) || proto[prop] !== obj[prop]);}return hasOwnProperty(x,'key')}
// src: https://stackoverflow.com/a/135568/860099function G(x) {return typeof(x.key) !== 'undefined'}
// src: https://stackoverflow.com/a/22740939/860099function H(x) {return x.key !== undefined}
// src: https://stackoverflow.com/a/38332171/860099function I(x) {return !!x.key}
// src: https://stackoverflow.com/a/41184688/860099function J(x) {return !!x['key']}
// src: https://stackoverflow.com/a/54196605/860099function K(x) {return Boolean(x.key)}

// --------------------// TEST// --------------------
let x1 = {'key': 1};let x2 = {'key': "1"};let x3 = {'key': true};let x4 = {'key': []};let x5 = {'key': {}};let x6 = {'key': ()=>{}};let x7 = {'key': ''};let x8 = {'key': 0};let x9 = {'key': false};let x10= {'key': undefined};let x11= {'nokey': 1};


let b= x=> x ? 1:0;
console.log('  1 2 3 4 5 6 7 8 9 10 11');
[A,B,C,D,E,F,G,H,I,J,K ].map(f=> {console.log(`${f.name} ${b(f(x1))} ${b(f(x2))} ${b(f(x3))} ${b(f(x4))} ${b(f(x5))} ${b(f(x6))} ${b(f(x7))} ${b(f(x8))} ${b(f(x9))} ${b(f(x10))}  ${b(f(x11))} `)})  
console.log('\nLegend: Columns (cases)');console.log('1.  key = 1 ');console.log('2.  key = "1" ');console.log('3.  key = true ');console.log('4.  key = [] ');console.log('5.  key = {} ');console.log('6.  key = ()=>{} ');console.log('7.  key = "" ');console.log('8.  key = 0 ');console.log('9.  key = false ');console.log('10. key = undefined ');console.log('11. no-key ');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"> </script>  
This shippet only presents functions used in performance tests - it not perform tests itself!

以下是chrome的示例结果

输入图片描述

迭代对象自身属性的更好方法:

如果你想在不使用hasOwnProperty()检查的情况下迭代对象的属性,使用for(let key of Object.keys(stud)){}方法:

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

完整示例和与for-in with hasOwnProperty()的比较

function Student() {this.name = "nitin";}
Student.prototype = {grade: 'A'}
let stud = new Student();
// for-in approachfor(let key in stud){if(stud.hasOwnProperty(key)){console.log(key); // only outputs "name"}}
//Object.keys() approachfor(let key of Object.keys(stud)){console.log(key);}

如何使用这个答案

const object= {key1: 'data', key2: 'data2'};
Object.keys(object).includes('key1') //returns true

我们也可以使用indexOf,我更喜欢包括

hasOwnProperty()//物权//物权方法返回一个布尔值,指示对象是否将指定的属性作为自己的属性(而不是继承它)。

const object1 = {};object1.property1 = 42;
console.log(object1.hasOwnProperty('property1'));// expected output: true
console.log(object1.hasOwnProperty('toString'));// expected output: false
console.log(object1.hasOwnProperty('hasOwnProperty'));// expected output: false

了解更多

给定myObject对象和"myKey"作为键名:

Object.keys(myObject).includes('myKey')

myObject.hasOwnProperty('myKey')

typeof myObject.myKey !== 'undefined'

最后一个被广泛使用,但是(正如在其他答案和评论中指出的那样)它也可以匹配从Object原型派生的键。

根据具体用例,一些更简单和简短的选项:

  1. 要检查属性是否存在,无论值如何,请使用在运算符中(b中的“a”)
  2. 要检查变量的属性值,请使用括号符号(obj[v])
  3. 若要检查属性值是否为truthy,请使用可选链接(?.)
  4. 要检查属性值boolean,请使用双不/砰-砰/(!!)
  5. 要为null/未定义检查设置默认值,请使用零合并算子(??)
  6. 要为false值检查设置默认值,请使用短路逻辑或运算符(||)

运行代码片段以查看结果:

let obj1 = {prop:undefined};console.log(1,"prop" in obj1);console.log(1,obj1?.prop);
let obj2 = undefined;//console.log(2,"prop" in obj2); would throw because obj2 undefinedconsole.log(2,"prop" in (obj2 ?? {}))console.log(2,obj2?.prop);
let obj3 = {prop:false};console.log(3,"prop" in obj3);console.log(3,!!obj3?.prop);
let obj4 = {prop:null};let look = "prop"console.log(4,"prop" in obj4);console.log(4,obj4?.[look]);
let obj5 = {prop:true};console.log(5,"prop" in obj5);console.log(5,obj5?.prop === true);
let obj6 = {otherProp:true};look = "otherProp"console.log(6,"prop" in obj6);console.log(6,obj6.look); //should have used bracket notation
let obj7 = {prop:""};console.log(7,"prop" in obj7);console.log(7,obj7?.prop || "empty"); 

我看到很少有hasOwn被正确使用的情况,特别是考虑到它的继承问题

现在有了ECMAScript22,我们可以使用已拥有而不是hasOwnProperty(因为这个特性有缺陷)

Object.hasOwn(obj, propKey)

x?. key返回1如果x.key存在,否则未定义