如何高效检查JavaScript对象中的键是否存在

0ca7baff3d047619e69914572898aa0f.jpeg

在日常开发中,作为一个JavaScript开发者,我们经常需要检查对象中某个键是否存在。这看似简单,但其实有多种方法可供选择,每种方法都有其独特之处。本文将介绍几种检查JavaScript对象键的方法,并比较它们的性能。

问题背景

假设我们有一个简单的对象:

 
 
const user = {
  name: 'John',
  age: 30 
};

我们想在访问name键之前检查它是否存在:

 
 
if (user.name) {
  console.log(user.name); 
}

这个方法表面上看没问题,但如果name键存在但值是undefined会怎样呢?

 
 
const user = {
  name: undefined
};


if (user.name) {
  // 这段代码不会执行!
}

直接访问一个不存在的键会返回undefined,但是访问值为undefined的键也是返回undefined。所以我们不能依赖直接键访问来检查键是否存在。

使用typeof

一种常见的方法是使用typeof来检查类型:

 
 
if (typeof user.name !== 'undefined') {
  console.log(user.name);
}

typeof会对不存在的键返回"undefined",对存在的键返回其它类型,如"string"。然而,这种方法有几个缺点:

  • 需要额外的操作(typeof)而不是直接比较

  • 比较冗长且需要否定检查(!==

  • 可读性不如其他方法

  • 容易拼写错误'undefined'

使用in操作符

in操作符允许我们检查键是否存在于对象中:

 
 
if ('name' in user) {
  console.log(user.name); 
}

这种方法比typeof更简洁:

  • 简单且可读

  • 内置语言特性,专为此设计

  • 对所有值都有效,包括undefined

但是,in操作符也会检查对象的原型链。因此它对原型链上存在的键也会返回true

使用hasOwnProperty

要仅检查对象自身的键,可以使用hasOwnProperty

 
 
if (user.hasOwnProperty('name')) {
  console.log(user.name);
}

这种方法只会返回对象自身拥有的键,而不会检查继承的属性:

  • 只检查自身键,不包括继承的

  • 方法名清晰,容易理解

缺点是hasOwnProperty需要方法调用,在性能关键的代码中可能会有影响。

性能比较

哪种方法最快呢?以下是直接键访问、inhasOwnPropertytypeof的简单性能比较:

 
 
const user = {
  name: 'John'  
};


let key = 'name';


function directAccess() {
  return user[key] !== undefined; 
}


function inOperator() {
  return key in user;
}


function hasOwnProperty() {
  return user.hasOwnProperty(key);
}


function typeofCheck() {
  return typeof user[key] !== 'undefined';
}


function objectKeysCheck() {
  return Object.keys(user).includes(key);
}


// 运行每个函数100万次
let start = performance.now();
for (let i = 0; i < 1000000; i++) {
  directAccess();
}
console.log(`directAccess took ${performance.now() - start} ms`);


start = performance.now();
for (let i = 0; i < 1000000; i++) {
  inOperator();
}
console.log(`inOperator took ${performance.now() - start} ms`);


start = performance.now();
for (let i = 0; i < 1000000; i++) {
  hasOwnProperty();
}
console.log(`hasOwnProperty took ${performance.now() - start} ms`);


start = performance.now();
for (let i = 0; i < 1000000; i++) {
  typeofCheck();
}
console.log(`typeofCheck took ${performance.now() - start} ms`);


start = performance.now();
for (let i = 0; i < 1000000; i++) {
  objectKeysCheck();
}
console.log(`objectKeysCheck took ${performance.now() - start} ms`);

结果如下( 测试机器:apple m1 ,内存16G):

  • directAccess耗时 1.59 毫秒

  • inOperator 耗时 0.97 毫秒(注:inOperator 和 typeofCheck 有时会比较接近)

  • hasOwnProperty耗时 4.74 毫秒

  • typeofCheck耗时 1.16 毫秒

  • Object.keys()耗时 8.48 毫秒

如上所示,inOperator 运算显著快于其他方法。

总结
  • 直接键访问较快且易读但无法处理undefined

  • in操作符最快但能处理所有值,包括undefined

  • hasOwnProperty较慢但只检查对象自身的键

  • typeof速度较快但需要冗长的否定检查

  • Object.keys()方法直观,但速度最慢

在大多数情况下,in操作符在可读性和性能之间提供了最佳平衡。只有在需要排除继承键时才使用hasOwnProperty

理解这些不同方法的细微差别是检查JavaScript键的关键。根据具体需求选择合适的工具,除非性能至关重要,否则应优先考虑可读性。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值