怎样判断一个变量是数组还是对象?

news2025/1/11 18:34:15

判断的基本方法

1. typeof(不可以)

通常情况下,我们第一时间会想到typeof运算符,因为typeof是专门用于类型检测的,但是typeof并不能满足这样的需求,比如

let a = ['7','4','1']
console.log(typeof(a))  //输出object
复制代码

2. instanceof

instanceof运算符用于通过查找原型链来检查某个变量是否为某个类型数据的实例,使用instanceof运算符可以判断一个变量是数组还是对象。

  var a = [1, 2, 3];
      console.log(a instanceof Array); // true
      console.log(a instanceof Object); // true
      //从此我们可以看出a既是数组,也是对象

  var userInfo = { userName: "zhangsan" };
      console.log(userInfo instanceof Array); // false
      console.log(userInfo instanceof Object); // true
      //userInfo只是对象,而不是数组
复制代码

基于以上逻辑,我们可以封装以下函数,用于判断变量是数组类型还是对象类型

var a = [1,2,3]
function getType(obj){
   if(obj instanceof Array){
       returen 'Array'//如果是数组,则返回数组类型
   }else if(obj instanceof Object){
       return 'Object'
   }else{
       return '既不是Array也不是Object'
   }
}
console.log(getType(a))
复制代码

最近一次面试中,面试老师追问,instanceof的底层原理是什么? 那我们就来浅挖一下instanceof的底层原理

2.1 instanceof底层是如何工作的:

在 MDN 上是这样描述 instanceof 的:

instanceof 运算符用于测试构造函数的 prototype 属性是否出现在对象原型链中的任何位置 换句话说,如果A instanceof B,那么 A 必须是一个对象,而 B 必须是一个合法的 JavaScript 函数。在这两个条件都满足的情况下:

判断 B 的 prototype 属性指向的原型对象(B.prototype)是否在对象 A 的原型链上。

如果在,则为 true;如果不在,则为 false。


function instance_of(L, R) {//L 表示左表达式,R 表示右表达式 
    var O = R.prototype;   // 取 R 的显示原型 
    L = L.__proto__;  // 取 L 的隐式原型
    while (true) {    
        if (L === null)      
             return false;   
        if (O === L)  // 当 O 显式原型 严格等于  L隐式原型 时,返回true
             return true;   
        L = L.__proto__;  
    }
}
复制代码

2.2 利用原型继承,切断了原来的prototype的指向,而指向了一个新的对象,这时instanceof又是如何进行判断的呢?

没有发生继承关系

 function Person(name,age,sex){
     this.name = name;
     this.age = age; 
     this.sex = sex;
 }
 function Student(score){
     this.score = score; 
  }
 var per = new Person("小明",20,“男”);
 var stu = new Student(98) 
 console.log(per instanceof Person);  // true
 console.log(stu instanceof Student);  // true
 console.log(per instanceof Object);  // true
 console.log(stu instanceof Object);  // true
复制代码

没有发生继承关系的原型图

 

发生了继承关系

 function Person(name,age,sex){
     this.name = name;
     this.age = age;
     this.sex = sex;
 }
 function Student(name,age,sex,score){
     Person.call(this,name,age,sex);  
     this.score = score;
  }
 Student.prototype = new Person();  // 这里改变了原型指向,实现继承
 var stu = new Student("小明",20,"男",99); //创建了学生对象stu
 console.log(stu instanceof Student);    // true
 console.log(stu instanceof Person);    // true
 console.log(stu instanceof Object);    // true
复制代码

发生继承关系后的原型图

 

发生继承后instanceof的工作流程分析:

首先看 stu instanceof Student

 function instance_of(L, R) { //L即stu ;  R即Student
   var O = R.prototype;  //O为Student.prototype,现在指向了per
    L = L.__proto__;    //L为stu._proto_,也随着prototype的改变而指向了per
    while (true) {    //执行循环
          if (L === null)  //不通过
              return false;   
          if (O === L)    //判断: Student.prototype ===stu._proto_?
              return true;  //此时,两方都指Person的实例对象per,所以true
          L = L.__proto__;                   
      }
 } 
复制代码

所以,即使发生了原型继承,stu instanceof Student 依然是成立的。

再看 stu instanceof Person,instanceof是如何判断stu继承了Person

 function instance_of(L, R) { // L即stu ;  R即Person        
   var O = R.prototype; // O为Person.prototype     
    L = L.__proto__;   //L为stu._proto_,现在指向的是per实例对象
    while (true) {   // 执行循环                   
       if (L === null)   //不通过                            
           return false;                    
       if (O === L)    //判断:   Person.prototype === stu._proto_ ?      
            return true;   //此时,stu._proto_ 指向per实例对象,并不满足
        L = L.__proto__;  //令L=  stu._proto_._proto_,执行循环
   }                      //stu._proto_ ._proto_,看图示知:
}                        //指的就是Person.prototype,所以也返回true
复制代码

2.3 结论

1、instanceof 的作用

用于判断一个引用类型是否属于某构造函数;

还可以在继承关系中用来判断一个实例是否属于它的父类型。

2、和typeof的区别:

typeof在对值类型numberstringobjectbooleanfunctionundefinedsymbol 这七种类型是精准的;但是,对于对象{ } 、数组[ ] 、null 都会返回object,为了弥补这一点,instanceof 从原型的角度,来判断某引用属于哪个构造函数,从而判定它的数据类型。

3.通过构造函数来判断

判断一个变量是否是数组还是对象,其实就是判断变量的构造函数是Array类型还是Object类型。 因为一个对象的实例都是通过构造函数创建的。 因为一个对象的实例都是通过构造函数创建的。

 var a = [1, 2, 3];
      console.log(a.__proto__.constructor === Array); //true
      console.log(a.__proto__.constructor === Object); // false
复制代码

同样这里,这里我们也可以封装一个函数,来判断变量是数组类型还是对象类型。

  function getType(o) {
        //获取构造函数
        var constructor = o.__proto__.constructor;
        if (constructor === Array) {
          return "Array";
        } else if (constructor === Object) {
          return "Object";
        } else {
          return "参数类型不是Array也不是Object";
        }
      }
      var a = [1, 2, 3];
      console.log(getType(a));
复制代码

4. 通过toString( )函数来判断

每种引用类型都会直接或间接继承Object类型,因此它们都包含toString( )函数。 不同数据类型的toString( )函数返回值也不一样,所以通过toString( )函数就可以判断一个变量是数组还是对象,当然,这里我们需要用到call方法来调用Object原型上的toString( )函数来完成类型的判断。

var arr = [1, 2, 3];
var obj = { userName: "zhangsan" };
console.log(Object.prototype.toString.call(arr)); //[object Array]
console.log(Object.prototype.toString.call(obj)); // [object Object]
console.log(arr.toString()); // 1,2,3
复制代码

5. 通过Array.isArray( )函数来判断

Array.isArray 方法用来判断变量是否为数组。 当检测Array实例时, Array.isArray 优于 instanceof,因为Array.isArray能检测iframes.

    var arr = [1, 2, 3];
      var obj = { name: "zhangsan" };
      console.log(Array.isArray(1)); //false
      console.log(Array.isArray(arr)); //true
      console.log(Array.isArray(obj)); //false
复制代码

以上内容仅供学习参考,如有错误欢迎大家指出

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/94704.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

以太网 VLAN的5种划分方式(基于端口、基于MAC地址、基于IP子网、基于协议、基于策略)介绍与基础配置命令

2.8.3 以太网 VLAN(VLAN划分方式) VLAN的划分方式有2.8.3 以太网 VLAN(VLAN划分方式)一、基于端口划分二、基于MAC地址划分三、基于IP子网划分四、基于协议划分五、基于策略划分一、基于端口划分 简述:端口上进行手动…

bitset位图的介绍与使用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录bitset的介绍位图的引入位图的概念位图的应用bitset的使用bitset的定义方式bitset的成员函数bitset运算符的使用如有错误,多多指教!bitset的介…

传奇GEE引擎微端架设教程

传奇GEE引擎微端架设教程 GEE引擎架设微端需要准备好微端程序,用网站下载在服务器的版本 Mirserver文件一般都是自带微端程序的,偶尔也有版本没有微端程序那我们只需要到别的版本或者资源把微端程序拉到我们的文件夹里面D:\Mirserver 这个就…

MyBatisPlus常用注解

MyBatisPlus常用注解 TableName:自定义表名 给User实体类添加注解 aplication.yml中添加mp的配置 # 配置mp的日志 mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl# 设置MyBatis-Plus的全局配置global-config:db-config:table…

java基础巩固-宇宙第一AiYWM:为了维持生计,架构知识+分布式微服务+高并发高可用高性能知识序幕就此拉开(三:注册中心balabala)~整起

比如咱们作为客户端进行购物时,那么多服务提供者【服务提供者有很多实例,可能人家已经搞了拆分模块后的分布式集群,那实例就不少啦】,如果用非技术的眼光看就是,你提供多个,我挑一个买,咱们的访…

立足浙江 辐射全国 护航数字经济发展|美创科技亮相首届数贸会

12月11日-14日,首届全球数字贸易博览会在杭州隆重召开。作为国内唯一经党中央、国务院批准的以数字贸易为主题的国家级、全球性专业博览会,首届数贸会由浙江省人民政府和商务部联合主办,杭州市人民政府、浙江省商务厅和商务部贸发局共同承办。…

EtherCAT设备协议详解二、EtherCAT状态机及配置流程

EtherCAT状态机(ESM) EtherCAT状态机定义了每个EtherCAT从站设备的分步设置,并指示了可用的功能。设备可以拒绝来自主站的状态请求,并通过错误指示(AL 状态寄存器中的错误标志)和相关错误代码(A…

Linux高级 I/O

目录 一、五种I/O模型 1. 阻塞式I/O 2. 非阻塞式I/O 3. I/O复用(多路转接) 4. 信号驱动式I/O 5. 异步I/O 二、五种I/O模型的比较 三、I/O复用典型使用在下列网络应用场合 一、五种I/O模型 阻塞式I/O非阻塞式I/OI/O复用(多路转接&a…

ios 计算label宽度方法效率对比

方式1: 设置好label的文字,字号等属性后,调用 self.label.text "111"; self.label.font [UIFont systemFontOfSize:17]; [self.label sizeToFit]; 方式2: 使用字符串的方法计算文字宽度, - (CGRect)boun…

TheFuck—Python写的超实用命令纠正工具

序言 哈喽兄弟们,我们在学习Python的过程中,有这么一款工具,可以轻松纠正我们写错的命令,简直太好用了~ The Fuck 是一款功能强大的、Python编写的应用程序,可用于纠正控制台命令中的错误,非常强大。此外…

Linux多线程(二):线程控制

文章目录一、前言二、认识线程控制函数1.线程创建2.线程退出3.线程等待4.查看线程id5.线程分离6.综合demo三、线程id本质是地址?一、前言 上篇博客谈到,Linux并没有真线程,而是通过复用进程的数据结构来模拟实现线程的。因此 Linux 自然不会提…

所有的为时已晚都是恰逢其时,社科院与杜兰大学金融管理硕士邀你在职读研

最近有咨询的同学询问,我年龄快35岁了读研晚吗?记得在网上看到过一句话,你觉得为时已晚的时候,恰恰是最早的时候。你可以确定一下你的内心,是不是真的想读研,既然迟早要读的话,与其等到了40、50…

ISO 15765-2协议分享(一)- TP时间参数详解

文章目录 前言一、时间参数协议定义二、使用步骤 1.引入库2.读入数据总结前言 无大志者常立志,让自己生活中时时有目标,有努力的方向。 老规矩,正文前分享喜欢的文字: 生活中,你越是去竭力回避不适的感觉,就越是难以推进生活中的重要转变。 不回避,积极面对,是提升自…

蓝奥声网关为什么会受到广大用户的欢迎?

蓝奥声GP20蓝牙网关是一款支持无线和有线连接的智能网关,配有独特的网口驱动,支持带有TCP/IP的以太网接口。用于互联网访问和与主机服务器的通信,用于远程命令和本地处理数据的数据上传/下载。它支持 RJ45/POE 和 WiFi 两种网络角色。 GP20蓝…

点面科技荣获优胜企业奖,圆满从2022“创·在上海”国际创新创业大赛之“创·加速营”毕业

创在上海 赢在未来 “创在上海”国际创新创业大赛暨中国创新创业大赛 (上海赛区) 是一项具有广泛影响力的创新创业活动。 为提升入围全国赛的参赛企业的参赛能力,“创在上海”将充分整合和调动多方资源,结合国赛进程,创新推出针对入围国赛企…

Git常用命令总结

配置git 本地创建 ssh key: ssh keygen -t rsa -c “email” // email:github上注册用的邮箱 把上面生成的 key 粘贴到 gitHUb中的 sshkey中 验证 是否成功 ssh -T gitgithub.com 如果是第一次的会 提示 是否continue ,输入 yes 就会看到 You’ve succe…

Springboot健康上报小程序: element后台管理系统(完整代码)

这几天接到了个学生的需求,挺简单的,大概就是按照她的需求做一个疫情期间常态化管理的小程序,由于我对java不熟悉,基本上是边做边学,这里我将对本次项目做个记录 ✨✨欢迎订阅本专栏或者关注我,大家一起努力…

内科大机器学习框架课程重点内容笔记

文章目录一.背景二.内容一.背景 这是2020届内科大机器学习框架课程的考试复习内容 二.内容 1.变量间的相互关系: (1)确定性关系或函数关系:研究的是确定现象非随机变量间的关系。 (2)相关关系或统计依赖关系:研究的是非确定现象随机变量间…

计算机毕设Python+Vue校园一卡通管理系统(程序+LW+部署)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

外滩金融峰会公布“第七届融城杯十佳案例”,工行、创邻科技等成功上榜

12月11日,由中国金融四十人论坛(CF40)主办的第四届外滩金融峰会在上海召开。国家副主席王岐山为峰会致开幕辞,中国人民银行原行长周小川、上海新金融研究院理事长屠光绍、中国人民银行副行长宣昌能、中央财经委员会办公室副主任尹…