整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

JavaScript-检查js对象中是否存在某key

JavaScript-检查js对象中是否存在某key?

ey的值有可能是undefined

单纯的if判定,可能存在key存在但值是undefined

let obj={ key: undefined };
obj["key"] !==undefined // false 但是key是存在的!

in

“property” in obj 可以判断一个对象是否有原生属性或者原型属性;

let obj={ key: undefined };
"key" in obj // true 

如果要检查键是否不存在,请记住使用括号

let obj={ key: undefined };
!("key" in obj) 
!"key" in obj 

hasOwnProperty

obj.hasOwnProperty(“property”) 返回布尔类型,用于判断某个对象上是否有某个属性,但是仅仅指的是实例化的属性,不包括原型上的属性,也不包括属性指向一个对象当中的属性

日常开发中,作为一个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键的关键。根据具体需求选择合适的工具,除非性能至关重要,否则应优先考虑可读性。

效果图:

2 html骨架:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!--网页标题-->
    <title>detection</title>
    <!--内部css部分-->
    <style>
    ......
    </style>
</head>

<body>
    <!--div部分-->
    <div class="contain">
    ......
    </div>

    <!--内部js部分-->
    <script>    
      ......
    </script>
</body>
</html>

3 css部分:

 <!--内部css部分-->
    <style>
        /*网页和body整体设置*/
        html,body{
            margin:0;
            padding:0;
            /*网页背景颜色设置*/
            background-color: rgb(96, 94, 212);
        }
        
        /*class='contain'在css的前面有点*/
        .contain{
            width:200px;
            height: 200px;
            font-size:25px;
            text-align: center;
            position: absolute;
            left:50%;
            top:50%;
            transform:translate(-50%,-50%);
            z-index:30;
        }

        /*警示label和结果label*/
        .alertInfo,.resultInfo{
            color:rgb(12, 231, 213);
            font-weight: bold;
            /*可以写在这里,注意数字和px紧紧相邻*/
            width: 350px;
            height: 10px;

        }
        
        /*输入框的设置*/
        .text{
            width:150px;
            /*文本框默认显示,下面就是不显示*/
            /*outline:none;*/ 
            text-align: center;
            font-size:25px;
            color:blue;
        }

        /*显示框的设置*/
        .show{
            font-size:25px;
            color:red;
        }
    </style>

4 body的div部分:

    <!--div部分-->
    <div class="contain">
        <!--注意:style可以嵌套在里面,但不推荐,也可以单独写在上面的css内-->
        <!--p class="alertInfo" style="width: 350px; height: 10px">显示倒5个字符串的输入框:</!--p-->
        <p class="alertInfo" >显示倒5个字符串的输入框:</p>
        <!--placeholder是指输入框默认显示文字-->
        <input type="text" class="text" placeholder="请输入内容">
        <!--p class="resultInfo" style="width: 350px; height: 10px">显示倒4个字符串的显示区:</!--p-->
        <p class="resultInfo" >显示倒4个字符串的显示区:</p>
        <p class="show"></p>
    </div>

5 body的js=JavaScript=script部分:

    <!--内部js部分-->
    <script>
        // 被let声明的变量不会作为全局对象window的属性,而被var声明的变量却可以
        //text和show均是class,所以前面有一个点
        let input=document.querySelector(".text");
        let show=document.querySelector(".show");
        input.addEventListener('keyup',debounce(handle,100));
        // 防抖处理
        function debounce(func,wait){
            let timeflag;
            return function(){
                clearTimeout(timeflag); //清除100ms之内之前触发的定时器。
                let arg=arguments;
                let timethis=this;
                timeflag=setTimeout(func.bind(timethis,arg),wait);
            }
        }
        //回调函数
        function handle(){
            //输入框内倒取5个字符串
            input.value=input.value.slice(-5);
            //输入框内倒取4个字符串
            show.textContent=input.value.slice(-4);
            
        }
    </script>

6 html部分基础学习,自己整理并分享出来。