JavaScript中如何判断一个对象是不是具有给定的属性

Posted

技术标签:

【中文标题】JavaScript中如何判断一个对象是不是具有给定的属性【英文标题】:How to determine whether an object has a given property in JavaScriptJavaScript中如何判断一个对象是否具有给定的属性 【发布时间】:2010-12-26 01:44:07 【问题描述】:

无论x.y 的值如何,如何确定对象x 是否具有定义的属性y

我正在使用

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

但这似乎有点笨拙。有没有更好的办法?

【问题讨论】:

不要用()、it is an operator而不是函数“调用”typeof 【参考方案1】:

除了其他答案,我想建议使用Object.hasOwn() 方法来检查指定对象是否具有指定属性作为其自己的属性(即对象本身),您可以使用新的Object.hasOwn() 方法是一个静态方法,如果指定对象具有指定属性作为其自己的属性,则返回 true。如果该属性是继承的,或者不存在,则该方法返回 false。

const person =  name: 'dan' ;

console.log(Object.hasOwn(person, 'name'));// true
console.log(Object.hasOwn(person, 'age'));// false

const person2 = Object.create(gender: 'male');

console.log(Object.hasOwn(person2, 'gender'));// false

建议在Object.hasOwnProperty() 上使用此方法,因为它也适用于使用Object.create(null) 创建的对象以及已覆盖继承的hasOwnProperty() 方法的对象。虽然可以通过在外部对象上调用Object.prototype.hasOwnProperty() 来解决这类问题,但Object.hasOwn() 克服了这些问题,因此是首选(参见下面的示例)

let person = 
  hasOwnProperty: function() 
    return false;
  ,
  age: 35
;

if (Object.hasOwn(person, 'age')) 
  console.log(person.age); // true - the remplementation of hasOwnProperty() did not affect the Object

let person = Object.create(null);
person.age = 35;
if (Object.hasOwn(person, 'age')) 
  console.log(person.age); // true - works regardless of how the object was created

更多关于Object.hasOwn的信息可以在这里找到:https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Global_Objects/Object/hasOwn

浏览器兼容性 - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn#browser_compatibility

检查指定属性是否存在于对象本身或原型链中可以通过in 运算符进行验证,正如其他答案所建议的那样。

【讨论】:

【参考方案2】:

与此线程中的其他示例不同,此实现仅断言该对象具有我们正在检查的属性。

const hasOwnProperty = <X extends , Y extends PropertyKey>(
  object: X,
  property: Y
): object is Record<Y, unknown> & X => 
  return object.hasOwnProperty(property);
;

这是一个用于识别具有所需属性的分支的示例。

const hasOwnProperty = <X extends , Y extends PropertyKey>(
  object: X,
  property: Y
): object is Record<Y, unknown> & X => 
  return object.hasOwnProperty(property);
;

type PaidProjectFeeType = 'FIXED_PRICE' | 'RATE' | '%future added value';

const PAID_PROJECT_FEE_TYPE_LABELS: Record<
  'FIXED_PRICE' | 'RATE',
  string
> = 
  FIXED_PRICE: 'Fixed Price',
  RATE: 'Rate',
;

export const getPaidProjectFeeTypeLabel = (
  feeType: PaidProjectFeeType
): string => 
  if (hasOwnProperty(PAID_PROJECT_FEE_TYPE_LABELS, feeType)) 
    PAID_PROJECT_FEE_TYPE_LABELS[feeType];
  

  throw new Error('test');
;

https://tsplay.dev/m0LBOm

令人讨厌的是,现在PAID_PROJECT_FEE_TYPE_LABELS 被假定为:

Record<PaidProjectFeeType, unknown> & Record<"FIXED_PRICE" | "RATE", string>

即您无法返回结果,因为X[Y] 的可能值是unknown。当您需要断言该对象具有所需的属性时,这很有用,但您需要添加更多断言以确保结果是您想要的。

不过,还有更好的方法。

我们将需要两个实用程序:

export const keys = <T extends Record<string, unknown>>(
  object: T
): Array<keyof T> => 
  return Object.keys(object);
;

keys 为我们提供了对象属性名称的类型化数组。

export const includes = <C extends M, M>(
  collection: readonly C[],
  member: M
): member is C => 
  return collection.includes(member as C);
;

includes 允许断言属性是只读数组的成员。您可以在此blog post 中阅读有关包含的更多信息。

export const keys = <T extends Record<string, unknown>>(
  object: T
): Array<keyof T> => 
  return Object.keys(object);
;

export const includes = <C extends M, M>(
  collection: readonly C[],
  member: M
): member is C => 
  return collection.includes(member as C);
;

type PaidProjectFeeType = 'FIXED_PRICE' | 'RATE' | '%future added value';

const PAID_PROJECT_FEE_TYPE_LABELS: Record<
  'FIXED_PRICE' | 'RATE',
  string
> = 
  FIXED_PRICE: 'Fixed Price',
  RATE: 'Rate',
;

export const getPaidProjectFeeTypeLabel = (
  feeType: PaidProjectFeeType
): string => 
  if (includes(keys(PAID_PROJECT_FEE_TYPE_LABELS), feeType)) 
    return PAID_PROJECT_FEE_TYPE_LABELS[feeType];
  

  throw new Error('test');
;

https://tsplay.dev/N7gLDN

简而言之,这种方法允许我们将feeType 的值缩小到keys(PAID_PROJECT_FEE_TYPE_LABELS) 中存在的值,然后允许我们访问属性值。

这种方法效果最好,但需要注意的是,从技术上讲,keys 实现不是运行时安全的。存在(大部分是理论上的)场景,运行时返回的值与使用 tsc 推断的值不同。

【讨论】:

感谢您抽出宝贵时间回答!最好能解释一下你的答案,而不仅仅是代码。【参考方案3】:

包括

Object.keys(x).includes('y');

Array.prototype.includes() 方法确定数组是否在其条目中包含某个值,根据需要返回 true 或 false。

Object.keys() 返回一个字符串数组,表示给定对象的所有可枚举属性。

.hasOwnProperty() 和 ES6+ ?. -optional-chaining like: if (x?.y) 也是非常好的 2020+ 选项。

【讨论】:

【参考方案4】:
const data = ["b":1,"c":100,"a":1,"b":1,"c":150,"a":1,"b":2,"c":100,"a":2,"b":1,"c":13]

const result = data.reduce((r, e)  => 
  r['a'] += (e['a'] ? e['a'] : 0)
    r['d'] += (e['b'] ? e['b'] : 0)
  r['c'] += (e['c'] ? e['c'] : 0)

  return r
, 'a':0, 'd':0, 'c':0)

console.log(result)
`result`  a: 4, d: 5, c: 363 

【讨论】:

【参考方案5】:

ES6+:

ES6+ 上有一个新特性,你可以像下面这样检查它:

if (x?.y)

实际上,解释器会检查x 的存在,然后调用y,因为在if 括号内会发生强制转换并将x?.y 转换为布尔值。

【讨论】:

如果 x.y 存在并且它是一个 falsy 值怎么办。【参考方案6】:

Underscore.js 或 Lodash

if (_.has(x, "y")) ...

:)

【讨论】:

不。它只是Object.prototype.hasOwnProperty.call(x, "y") 的别名。对于数组,我认为您可能需要 Array.prototype.indexOf_.indexOf_.contains【参考方案7】:

为什么不简单:

if (typeof myObject.myProperty == "undefined") alert("myProperty is not defined!");

或者,如果您期望特定类型:

if (typeof myObject.myProperty != "string") alert("myProperty has wrong type or does not exist!");

【讨论】:

因为它不好阅读并且不严格输入。我必须问你:为什么不简单地x.hasOwnProperty('y')【参考方案8】:

由于问题是关于属性检查的笨拙,以及一个用于验证函数参数选项对象的常规用例,我想我会提到一种测试多个属性是否存在的无库的简短方法。 免责声明:它确实需要 ECMAScript 5(但 IMO 任何仍在使用 IE8 的人都应该被破坏网络)。

function f(opts) 
  if(!["req1","req2"].every(opts.hasOwnProperty, opts)) 
      throw new Error("IllegalArgumentException");
  
  alert("ok");

f(req1: 123);  // error
f(req1: 123, req2: 456);  // ok

【讨论】:

【参考方案9】:

对象有属性:

如果您正在测试对象本身(不是其原型链的一部分)上的属性,您可以使用.hasOwnProperty()

if (x.hasOwnProperty('y'))  
  // ......

对象或其原​​型有一个属性:

您也可以使用in 运算符来测试继承的属性。

if ('y' in x) 
  // ......

【讨论】:

或者更好——Object.prototype.hasOwnProperty.call(x, 'y'),这样名为“hasOwnProperty”的属性就不会与检查过程发生冲突;) 甚至更短——.hasOwnProperty.call(x, 'y'). eslint.org/docs/rules/no-prototype-builtins【参考方案10】:

我的原始代码的一个功能

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

在某些情况下可能有用的是,无论x 是否存在,使用它都是安全的。使用 gnarf 答案中的任何一种方法,如果有任何疑问,应该首先测试 x 是否存在。

所以也许这三种方法都在一个人的花招中占有一席之地。

【讨论】:

你总是可以使用(x &amp;&amp; x.hasOwnProperty('y'))(x &amp;&amp; 'y' in x) 我同意,对 x 的测试应该是一个单独的案例。还可以生成更好的错误报告。 这对我来说失败了。如果 x 未定义,则 typeof(x.y) 返回 ReferenceError 而不是字符串 'undefined'【参考方案11】:

如果您想知道对象是否在物理上 包含属性@gnarf's,则使用hasOwnProperty 回答即可。

如果您想知道该属性是否存在于任何地方,无论是在对象本身上还是在原型链中,您可以使用in operator。

if ('prop' in obj) 
  // ...

例如:

var obj = ;

'toString' in obj == true; // inherited from Object.prototype
obj.hasOwnProperty('toString') == false; // doesn't contains it physically

【讨论】:

【参考方案12】:

你可以像这样修剪一下:

if ( x.y !== undefined ) ...

【讨论】:

x = y:undefined 会失败 有人需要区分“未定义”和“定义为未定义”吗? @darkporter 我有时会这样做 ;) @jpsimons for and instance "defined to be undefined" 由 Firestore 在保存文档数据时使用。

以上是关于JavaScript中如何判断一个对象是不是具有给定的属性的主要内容,如果未能解决你的问题,请参考以下文章

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

如何使用 JavaScript 判断 DOM 对象是不是在窗口外? [复制]

JavaScript中如何判断一个值是不是是Object Literal? [复制]

如何在 JavaScript 中判断一个对象是否为空?

js中如何判断一个DOM对象是不是存在?

js中如何判断一个属性是不是属于某个对象