如何检查对象是否在 JavaScript 中具有特定属性?
考虑:
x = {'key': 1};
if ( x.hasOwnProperty('key') ) {
//Do this
}
这是最好的方法吗?
in
和 hasOwnProperty
比其他人慢了 方式(慢了 98%)。我对 hasOwnProperty
变慢并不感到惊讶,但我对 in
感到惊讶。
Object.hasOwn
,它解决了 Object.prototype.hasOwnProperty
的一些问题。
2022 更新
与其在 100 万个重复的答案中添加另一个答案,我只想在这里添加评分最高的答案,即截至 2022 年还有另一个选择
Object.hasOwn()
没有必要重新发明轮子,所以我给你[MDN版本][1]:
推荐使用 Object.hasOwn() 而不是 Object.hasOwnProperty(),因为它适用于使用 Object.create(null) 创建的对象以及覆盖了继承的 hasOwnProperty() 方法的对象。虽然可以通过在外部对象上调用 Object.prototype.hasOwnProperty() 来解决这些问题,但 Object.hasOwn() 更直观。
我补充说它在语法上看起来也更干净。
约翰·雷西格的回答:
我真的对给出的答案感到困惑——其中大多数都是完全不正确的。当然,您可以拥有具有 undefined、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 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
的一个有效的跨浏览器解决方案,但有一个警告:它无法区分原型和实例上的相同属性的情况 - 它只是假设它来自原型。您可以根据您的情况将其更改为更宽松或更严格,但至少这应该更有帮助。
使用 Underscore.js 或 (even better) 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
npm install lodash.has
,它公开了一个 npm 模块,其中只有一个 has
函数,在缩小时编译到 175 字节。查看 lodash.has/index.js
以了解一个非常受欢迎和值得信赖的库是如何工作的,这也很有见地。
lodash
的版本适用于此:.has(undefined, 'someKey') => false
而 underscore
返回 undefined
lodash
添加为“又一个”依赖项的人:对于这类事情,它是一个相当常见的(如果不是最常见的)库。玩得开心重新发明轮子。
利用:
var x = {'key': 1 }; if ('key' in x) { console.log('has'); }
in
运算符。另请注意,in
运算符具有出色的浏览器支持 IE 5.5+, Chrome 1.0+, Firefox 1.0+, Safari 3.0+
stackoverflow.com/questions/2920765/…
in
还检查原型属性,而 hasOwnProperty
仅迭代用户定义的属性。参考:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
'key' in x
做 使用数组。证明:stackoverflow.com/questions/33592385/…
注意:由于严格模式和hasOwnProperty
,以下内容如今已基本过时。正确的解决方案是使用严格模式并使用 obj.hasOwnProperty
检查属性是否存在。这个答案早于这两件事,至少被广泛实施(是的,它就是那么旧)。将以下内容作为历史记录。
请记住,如果您不使用严格模式,undefined
(很遗憾)不是 JavaScript 中的保留字。因此,某人(显然是其他人)可能有重新定义它的宏伟想法,从而破坏您的代码。
因此,更稳健的方法如下:
if (typeof(x.attribute) !== 'undefined')
另一方面,这种方法更冗长,也更慢。 :-/
一种常见的替代方法是确保 undefined
实际上未定义,例如,将代码放入一个函数中,该函数接受一个称为 undefined
的附加参数,该参数未传递值。为确保它没有传递值,您可以立即自己调用它,例如:
(function (undefined) {
… your code …
if (x.attribute !== undefined)
… mode code …
})();
void 0
被定义为返回规范 undefined
,可以做 x.attribute !== void 0
吗?
(function (undefined) { // undefined is actually undefined here })();
if (x.key !== undefined)
Armin Ronacher 似乎已经有 beat me to it,但是:
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!');
}
Konrad Rudolph 和 Armin Ronacher 的 as pointed out 更安全但更慢的解决方案是:
Object.prototype.hasOwnProperty = function(property) {
return typeof this[property] !== 'undefined';
};
x.hasOwnProperty('toString') === true;
Object.prototype
已经有一个内置的、正确的 hasOwnProperty
。用不正确的实现覆盖它(1. 属性可以有值 undefined
,2. 这会给继承的属性带来误报)只是一个非常糟糕的主意。不正确的答案可以而且应该被删除。我不知道您是否可以在 08 年 9 月 when you saw Resig's answer 中执行此操作,因此发表评论建议现在执行此操作。
考虑 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);
这将返回对象上存在的所有属性的名称数组。
Reflections 提供可用于与 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");
}
这应该可以工作,除非在 x 对象上将 key 专门设置为 undefined
让我们在这里消除一些混乱。首先,让我们假设 hasOwnProperty
已经存在来简化;当前使用的绝大多数浏览器都是如此。
如果传递给它的属性名称已添加到对象,hasOwnProperty
将返回 true。它完全独立于分配给它的实际值,可能恰好是 undefined
。
因此:
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
将是假的,!== undefined
也是如此。然而,for..in
仍会在枚举中列出它。
底线是没有跨浏览器的方式(因为 Internet Explorer 不公开 __prototype__
)来确定特定标识符尚未附加到对象或其原型链中的任何内容。
如果您正在寻找房产,那么“不”。你要:
if ('prop' in obj) { }
通常,您不应该关心属性是来自原型还是来自对象。
但是,因为您在示例代码中使用了 'key',所以看起来您将对象视为哈希,在这种情况下,您的答案是有意义的。所有哈希键都是对象中的属性,您可以避免原型贡献的额外属性。
John Resig's answer 非常全面,但我认为不清楚。尤其是何时在 obj 中使用“'prop'”。
in
运算符具有出色的浏览器支持 IE 5.5+, Chrome 1.0+, Firefox 1.0+, Safari 3.0+
stackoverflow.com/questions/2920765/…
in
运算符的评论中指出的那样:“它适用于狭义的‘对象’,因此声明为 {} 或使用构造函数创建,它不接受数组或原语。不是 OP 要求它,但其他一些答案提供了更广泛的技术(使用数组、字符串等)”
要测试简单对象,请使用:
if (obj[x] !== undefined)
如果您不知道它是什么对象类型,请使用:
if (obj.hasOwnProperty(x))
所有其他选项都较慢...
细节
对 Node.js 下 100,000,000 次循环的性能评估,这里有其他人建议的五个选项:
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])...
,因为我发现它更具可读性。
是的 :) 我认为你也可以做 Object.prototype.hasOwnProperty.call(x, 'key')
如果 x
有一个名为 hasOwnProperty
的属性也应该工作 :)
但这会测试自己的属性。如果您想检查它是否具有也可能被继承的属性,您可以使用 typeof x.foo != 'undefined'
。
您还可以使用 the ES6 Reflect
object:
x = {'key': 1};
Reflect.has( x, 'key'); // returns true
Reflect.has
的 MDN 文档可以在 here 中找到。
静态 Reflect.has() 方法的工作方式类似于 in 运算符作为函数。
不要这样做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/has
console.log(has(object, key));
if(x.hasOwnProperty("key")){
// …
}
因为
if(x.key){
// …
}
如果 x.key
为假(例如 x.key === ""
),则失败。
好的,除非您不想要继承的属性,否则我似乎有正确的答案:
if (x.hasOwnProperty('key'))
以下是包含继承属性的其他一些选项:
if (x.key) // Quick and dirty, but it does the same thing as below.
if (x.key !== undefined)
var x = { key: false };
,x.key
方法不正确。
另一种相对简单的方法是使用 Object.keys
。这将返回一个 array
,这意味着您可以获得数组的所有功能。
var noInfo = {};
var info = {something: 'data'};
Object.keys(noInfo).length //returns 0 or false
Object.keys(info).length //returns 1 or true
尽管我们所处的世界拥有强大的浏览器支持。因为这个问题太老了,我想我会添加这个:从 JavaScript v1.8.5 开始可以安全使用。
Object.keys(info).indexOf('someotherthing') !== -1
JavaScript 现在正在发展和成长,因为它现在有很好的甚至有效的方法来检查它。
以下是检查对象是否具有特定属性的一些简单方法:
使用 hasOwnProperty()
const hero = {
name: 'Batman'
};
hero.hasOwnProperty('name'); // => true
hero.hasOwnProperty('realName'); // => false
在中使用关键字/运算符
const hero = {
name: 'Batman'
};
'name' in hero; // => true
'realName' in hero; // => false
与未定义的关键字比较
const hero = {
name: 'Batman'
};
hero.name; // => 'Batman'
hero.realName; // => undefined
// So consider this
hero.realName == undefined // => true (which means property does not exists in object)
hero.name == undefined // => false (which means that property exists in object)
有关详细信息,请查看 here。
hasOwnProperty “可用于确定一个对象是否具有作为该对象的直接属性的指定属性;与 in 运算符不同,此方法不会向下检查对象的原型链。”
因此,很可能,对于您的问题,您不想使用 hasOwnProperty,它确定属性是否直接附加到对象本身。
如果您想确定该属性是否存在于原型链中,您可能希望像这样使用它:
if (prop in object) { // Do something }
您可以使用以下方法 -
var obj = {a:1}
console.log('a' in obj) // 1
console.log(obj.hasOwnProperty('a')) // 2
console.log(Boolean(obj.a)) // 3
以下方法之间的区别如下 -
在第一种和第三种方法中,我们不仅在对象中搜索,而且也在其原型链中进行搜索。如果对象没有该属性,但该属性存在于它的原型链中,它将给出 true。
var obj = { a: 2, __proto__ : {b: 2} } console.log('b' in obj) console.log(Boolean(obj.b))
第二种方法将仅检查其自身的属性。例子 -
var obj = { a: 2, __proto__ : {b: 2} } console.log(obj.hasOwnProperty('b'))
第一种和第三种方法的区别在于,如果有一个属性的值未定义,第三种方法将给出假,而第一种方法将给出真。
var obj = { b : undefined } console.log(Boolean(obj.b)) console.log('b' in obj);
Boolean({b:''}.b) -> false
表现
今天 2020.12.17,我在 Chrome v87、Safari v13.1.2 和 Firefox v83 上对 MacOs HighSierra 10.13.6 进行测试,以选择解决方案。
结果
我只比较解决方案 AF,因为它们为详细信息部分的片段中使用的所有大小写提供了有效结果。适用于所有浏览器
基于(A)中的解决方案是快速或最快的
解决方案(E)对于大对象的 chrome 是最快的,如果 key 不存在,对于小数组的 firefox 是最快的
对于小型阵列,解决方案 (F) 最快(~ > 10 倍于其他解决方案)
解决方案(D,E)非常快
基于 losash 的解决方案 (B) 最慢
https://i.stack.imgur.com/dmfF0.png
细节
我执行 4 个测试用例:
当对象有 10 个字段并且搜索到的键存在时 - 你可以在这里运行它
当对象有 10 个字段并且搜索到的键不存在时 - 您可以在此处运行它
当对象有 10000 个字段并且存在搜索到的键时 - 您可以在此处运行它
当对象有 10000 个字段并且存在搜索到的键时 - 您可以在此处运行它
下面的代码段显示了解决方案之间的差异 A B C D E F G H I J K
// 所以 https://stackoverflow.com/q/135448/860099 // src: https://stackoverflow.com/a/14664748/860099 function A(x) { return 'key' in x } // src: https://stackoverflow.com/a/11315692/860099 function B(x) { return _.has(x, 'key') } // src: https://stackoverflow.com/a/40266120/860099 function C (x) { return Reflect.has( x, 'key') } // src: https://stackoverflow.com/q/135448/860099 function D(x) { return x.hasOwnProperty('key') } / /src: https://stackoverflow.com/a/11315692/860099 function E(x) { return Object.prototype.hasOwnProperty.call(x, 'key') } // src: https://stackoverflow.com/ a/136411/860099 函数 F(x) { 函数 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/860099 function G(x) { return typeof(x.key) !== 'undefined' } // src: https://stackoverflow.com/a/22740939/860099 function H(x) { return x.key !== undefined } // src: https://stackoverflow.com/a/38332171/860099 function I( x) { return !!x.key } // src: https://stackoverflow.com/a/41184688/860099 function J(x) { return !!x['key'] } // src: https:// /stackoverflow.com/a/54196605/860099 function K(x) { return Boolean(x.key) } // -------------------- // TEST / / -------------------- 让 x1 = {'key': 1};让 x2 = {'key': "1"};让 x3 = {'key': true};让 x4 = {'key': []};让 x5 = {'key': {}};让 x6 = {'key': ()=>{}};让 x7 = {'key': ''};让 x8 = {'key': 0};让 x9 = {'key': false};让 x10= {'key': undefined};让 x11= {'nokey': 1};让 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 ');
var w = opts.w || 100;
之类的操作。但是,如果您正在研究图书馆之类的东西,则可能需要在某些部分走得更远一些。__proto__
是非标准的,在某些较旧的浏览器中不起作用。即使最近添加了Object.getPrototypeOf
,该标准仍表示您仍然无法更改现有对象的原型。hasOwnProperty() "is not supported on host objects for Internet Explorer 8 and below"
看到 msdn.microsoft.com/en-us/library/ie/328kyd6z(v=vs.94).aspx 和 stackoverflow.com/questions/8157700/…for(prop in object)
循环仅迭代可枚举属性。但是,prop in object
会检查object
在原型链中的某处是否具有属性prop
,这与它是否可枚举无关。in
检查。