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

1818

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

考虑以下代码:

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

那是最好的做法吗?


31
我写了一个 jsperf 测试,用大家的答案来看哪个最快:http://jsperf.com/dictionary-contains-key - styfle
('propertyName' in Object) ? '属性存在' : '属性不存在' - Mohan Ram
2
@styfle 感谢你提供的jsperf测试。对我来说,“in”和“hasOwnProperty”的速度比其他方法慢得多(慢了98%)。我对“hasOwnProperty”较慢并不感到惊讶,但我对“in”较慢感到惊讶。 - evanrmurphy
3
有一个新的第三阶段提案,Object.hasOwn,它解决了Object.prototype.hasOwnProperty的一些问题。 - Sebastian Simon
32个回答

4

性能

今天2020年12月17日,我在Chrome v87、Safari v13.1.2和Firefox v83上对所选解决方案进行了MacOs HighSierra 10.13.6的测试。

结果

我仅比较A-F的解决方案,因为它们对详细部分中使用的所有情况都给出了有效的结果。所有浏览器都适用。

  • 基于in(A)的解决方案最快或者是最快的
  • 对于大型对象,解决方案(E)在Chrome中最快,在Firefox中对于小数组且键不存在时最快
  • 对于小型数组,解决方案(F)是最快的(~>10x than other solutions)
  • 解决方案(D,E)相当快
  • 基于lodash has(B)的解决方案最慢

enter image description here

详细信息

我执行了4个测试案例:

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

下面的代码段介绍了解决方案之间的差异: A B C D E F G H I J K

// SO https://dev59.com/_HVC5IYBdhLWcg3w9GHM


// src: https://dev59.com/_HVC5IYBdhLWcg3w9GHM#14664748
function A(x) {
  return 'key' in x
}

// src: https://dev59.com/_HVC5IYBdhLWcg3w9GHM#11315692
function B(x) {
  return _.has(x, 'key')
}

// src: https://dev59.com/_HVC5IYBdhLWcg3w9GHM#40266120
function C(x) {
  return Reflect.has( x, 'key')
}

// src: https://dev59.com/_HVC5IYBdhLWcg3w9GHM
function D(x) {
  return x.hasOwnProperty('key')
}

// src: https://dev59.com/_HVC5IYBdhLWcg3w9GHM#11315692
function E(x) {
  return Object.prototype.hasOwnProperty.call(x, 'key')
}

// src: https://dev59.com/_HVC5IYBdhLWcg3w9GHM#136411
function 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://dev59.com/_HVC5IYBdhLWcg3w9GHM#135568
function G(x) {
  return typeof(x.key) !== 'undefined'
}

// src: https://dev59.com/_HVC5IYBdhLWcg3w9GHM#22740939
function H(x) {
  return x.key !== undefined
}

// src: https://dev59.com/_HVC5IYBdhLWcg3w9GHM#38332171
function I(x) {
  return !!x.key
}

// src: https://dev59.com/_HVC5IYBdhLWcg3w9GHM#41184688
function J(x) {
  return !!x['key']
}

// src: https://dev59.com/_HVC5IYBdhLWcg3w9GHM#54196605
function 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的示例结果:

在此输入图片描述


3

这里是另一种特定情况的选项。:)

如果你想测试一个对象上的成员,并且想知道它是否已经被设置为非以下内容:

  • ''
  • false
  • null
  • undefined
  • 0 ...

那么你可以使用:

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

紧凑而方便 - Frederik Witte
1
一个代码检查工具不会喜欢这个:https://eslint.org/docs/rules/no-extra-boolean-cast - Wilt

3

根据具体用例,以下是一些更简单、更短的选项:

  1. 检查属性是否存在,无论其值如何,使用in 运算符("a" in b)
  2. 从变量中检查属性值,使用括号表示法(obj[v])
  3. 将属性值作为真值进行检查,使用可选链(?.)
  4. 将属性值作为布尔值进行检查,使用双非 / bang-bang / (!!)
  5. 为 null / undefined 检查设置默认值,使用nullish 合并运算符 (??)
  6. 为 falsey 值检查设置默认值,使用短路逻辑的逻辑或运算符(||)

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

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 undefined
console.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被正确使用,特别是考虑到它的继承问题


3

尽管有30个答案试图解释hasOwn和hasOwnProperty之间的区别,但我仍然很难理解它们之间的区别。这里是一个可运行的代码片段,你可以自己看看它的行为。

const object1 = {
  prop: 'exists'
};
object1.property1 = 42;

// the following as you might expect output true
console.log(object1.hasOwnProperty('property1'));
console.log(Object.hasOwn(object1,"prop"));
console.log(Object.hasOwn(object1,"property1"));

// the following might surpize you, they output false
console.log(Object.hasOwnProperty(object1,"prop"));
console.log(Object.hasOwnProperty(object1,"property1"));

// the following as you rightfully expect output false
console.log(object1.hasOwnProperty('toString'));
console.log(Object.hasOwn(object1,"toString"));
console.log(Object.hasOwnProperty(object1,"toString"));

console.log(object1.hasOwnProperty('hasOwnProperty'));
console.log(Object.hasOwn(object1,"hasOwnProperty"));
console.log(Object.hasOwnProperty(object1,"hasOwnProperty"));


2
展示如何使用这个答案
const object= {key1: 'data', key2: 'data2'};

Object.keys(object).includes('key1') //returns true

我们也可以使用indexOf,但我更喜欢includes

2

有一个方法叫做“hasOwnProperty”,它存在于对象上,但不建议直接调用该方法,因为有时可能会出现对象为空或某些属性存在于对象上的情况,例如:{ hasOwnProperty: false }

因此,更好的方式是:

// Good
var obj = {"bar": "here bar desc"}
console.log(Object.prototype.hasOwnProperty.call(obj, "bar"));

// Best
const has = Object.prototype.hasOwnProperty; // Cache the lookup once, in module scope.
console.log(has.call(obj, "bar"));


2

使用反射的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

在面向>= ES6的情况下,这是最好的做法吗? - hippietrail
1
在我看来,这是最短、最简单的答案,但可能不是执行代码最快的方式。但速度已经不再是问题了。 - Harm
为什么要发两次相同的答案?你不可以直接给现有的答案点赞吗...? - Wilt

1

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


1
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

了解更多


0

当你可以这样做时,不要过于复杂化事情:

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

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


最简单的是 var isProperty = !!objectname.keyname; - John
1
如果对象如下 const objectName = { keyname: false };,它应该返回 true,因为 keynameobjectname 的一个属性。但是由于值是 false,根据这个逻辑它将返回 false。 - Wilt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接