【发布时间】:2010-12-26 01:44:07
【问题描述】:
无论x.y 的值如何,如何确定对象x 是否具有定义的属性y?
我正在使用
if (typeof(x.y) !== 'undefined')
但这似乎有点笨拙。有没有更好的办法?
【问题讨论】:
-
不要用
()、it is an operator而不是函数“调用”typeof
标签: javascript object
无论x.y 的值如何,如何确定对象x 是否具有定义的属性y?
我正在使用
if (typeof(x.y) !== 'undefined')
但这似乎有点笨拙。有没有更好的办法?
【问题讨论】:
()、it is an operator而不是函数“调用”typeof
标签: javascript object
除了其他答案,我想建议使用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
检查指定属性是否存在于对象本身或原型链中可以通过in 运算符进行验证,正如其他答案所建议的那样。
【讨论】:
与此线程中的其他示例不同,此实现仅断言该对象具有我们正在检查的属性。
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');
};
令人讨厌的是,现在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');
};
简而言之,这种方法允许我们将feeType 的值缩小到keys(PAID_PROJECT_FEE_TYPE_LABELS) 中存在的值,然后允许我们访问属性值。
这种方法效果最好,但需要注意的是,从技术上讲,keys 实现不是运行时安全的。存在(大部分是理论上的)场景,运行时返回的值与使用 tsc 推断的值不同。
【讨论】:
包括
Object.keys(x).includes('y');
Array.prototype.includes() 方法确定数组是否在其条目中包含某个值,根据需要返回 true 或 false。
和
Object.keys() 返回一个字符串数组,表示给定对象的所有可枚举属性。
.hasOwnProperty() 和 ES6+ ?. -optional-chaining like: if (x?.y) 也是非常好的 2020+ 选项。
【讨论】:
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 }
【讨论】:
ES6+ 上有一个新特性,你可以像下面这样检查它:
if (x?.y)
实际上,解释器会检查x 的存在,然后调用y,因为在if 括号内会发生强制转换并将x?.y 转换为布尔值。
【讨论】:
x.y 存在并且它是一个 falsy 值怎么办。
Underscore.js 或 Lodash
if (_.has(x, "y")) ...
:)
【讨论】:
Object.prototype.hasOwnProperty.call(x, "y") 的别名。对于数组,我认为您可能需要 Array.prototype.indexOf、_.indexOf 或 _.contains
为什么不简单:
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')?
由于问题是关于属性检查的笨拙,以及一个用于验证函数参数选项对象的常规用例,我想我会提到一种测试多个属性是否存在的无库的简短方法。 免责声明:它确实需要 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
【讨论】:
如果您正在测试对象本身(不是其原型链的一部分)上的属性,您可以使用.hasOwnProperty():
if (x.hasOwnProperty('y')) {
// ......
}
您也可以使用in 运算符来测试继承的属性。
if ('y' in x) {
// ......
}
【讨论】:
Object.prototype.hasOwnProperty.call(x, 'y'),这样名为“hasOwnProperty”的属性就不会与检查过程发生冲突;)
{}.hasOwnProperty.call(x, 'y').
我的原始代码的一个功能
if ( typeof(x.y) != 'undefined' ) ...
在某些情况下可能有用的是,无论x 是否存在,使用它都是安全的。使用 gnarf 答案中的任何一种方法,如果有任何疑问,应该首先测试 x 是否存在。
所以也许这三种方法都在一个人的花招中占有一席之地。
【讨论】:
(x && x.hasOwnProperty('y')) 或(x && 'y' in x)
ReferenceError 而不是字符串 'undefined'
如果您想知道对象是否在物理上 包含属性@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
【讨论】:
你可以像这样修剪一下:
if ( x.y !== undefined ) ...
【讨论】:
x = {y:undefined} 会失败