js当中的类型判断

第一种:type of

1.判断原始类型

我们来看一段代码

js 复制代码
           console.log(typeof(23))
           console.log(typeof (NaN))
           console.log(typeof (true))
           console.log(typeof ('Hello world'))
           console.log(typeof (null))
           console.log(typeof (undefined))

我们来看一下执行结果

type of 可以判断除了null以外的所有原始类型

2.判断引用类型

js 复制代码
          let obj ={}
          let arr=[]
          let date= new Date()
          let fn =function(){

          }
           console.log(typeof (obj))
           console.log(typeof (arr))
           console.log(typeof (date))
           console.log(typeof (fn))

来看一下执行结果

type of 除了function 之外,所有引用类型都会判断成object

问题来了,为什么会这样呢?

原理:事实上,计算机在用type of 判断数据类型时,首先会把数据转化为二进制

原始类型转化二进制前三位一定不是0

引用类型转化为二进制前三位一定是0

type of 总共三句话

1.type of 可以判断除null之外所有的原始类型

2.type of 除了function 其他所有的引用类型都会被判成object

3.type of是通过将值转化为二进制后判断二进制前三位是否为0,是则为object

第二种:instance of

我们来看一段代码

js 复制代码
       
      let num =123
        let string ='hello'  
        let boolen =true 
        let arr=[]
        let obj={}


          console.log(num instanceof Number)
          console.log(string instanceof Number)
          console.log(boolen instanceof Number)

          console.log(arr instanceof Object)
          console.log(obj instanceof Object)

执行结果

说明 instance of 只能判断引用类型数据类型,不能判断基本数据类型

同样的,我们得搞清楚其中的原理

有小伙伴可能会疑惑,为什么 arr instanceof Object 也是true呢?arr是怎么关联到Object的呢?

事实上,这涉及到原型

js 复制代码
      arr.__proto__= Array.prototype
     Array.prototype.__proto__=Object.prototype

这就解决了上面那个问题,为什么instance of 不能判断原始类型呢?

因为原始数据类型没有原型,只有引用数据类型有原型

所以instance of 只能判断引用类型

如果没有instance of ,面试官让你手写以一个类似的 instance of 方法,你该怎么办呢?

js 复制代码
function  myInstanceof (L,R){
       while(L!== null){

         if(L.__proto__===R.prototype){
          return true
         }
         L=L.__proto__
       }
       return false
    }
  

myInstanceof([],Array)
  • 函数接收两个参数:LR。在这里,L 表示要检查的对象(左操作数),而 R 表示构造函数(右操作数)。
  • while 循环中,条件是 L !== null。这是因为当对象的原型链走到尽头时,它会指向 null。只要 L 不是 null,循环就会继续。
  • 在循环体内,使用 if 语句来检查 L 对象的原型(L.__proto__)是否等于 R 构造函数的原型(R.prototype)。如果相等,这意味着 L 实例化自 R 或其原型链上的某个构造函数,所以函数返回 true
  • 如果在当前层级没有找到匹配,将 L 设置为其自身的原型(L.__proto__),然后循环继续到下一层级。
  • 如果循环结束都没有找到匹配,说明 L 的原型链上没有任何构造函数的原型与 R.prototype 相等,因此函数返回 false

第三种:Object.prototype.toString.call()

万能方法:可以判断所有类型

原理:

具体原理

在toString方法被调用时,会执行以下几个操作步骤~

  1. 获取this指向的那个对象的[[Class]]属性的值。 (这也是我们为什么要用call改变this指向的原因)
  2. 计算出三个字符串"[object "、 第一步的操作结果Result(1)、 以及 "]" 连接后的新字符串。
  3. 返回第二步的操作结果Result(2),也就是类似 [object className] 这种格式字符串。

[[Class]] 类属性

对象的类属性(class attribute)是一个字符串,用以表示对象的类型信息。ES3和ES5都没有提供设置这个属性的方法,并只有一种间接的方法可以查询到它。默认的toString方法(继承自Object.prototype)返回了如下格式的字符串:[object class] 因此,想要获得对象的类,可以调用对象的toString方法,然后提取已返回字符串的第8个到倒数第2个位置之间的字符。

javascript 复制代码
js
Object.prototype.toString.call(target).slice(8, -1);

综上,[[Class]]是一个字符串值,表明了该对象的类型。他是一个内部属性,所有的对象(原生对象和宿主对象)都拥有该属性,且不能被任何人修改。在规范中,[[Class]]是这么定义的:内部属性 描述

宿主对象也包含有意义的"类属性",但这和具体的JavaScript实现有关。

因为js中每个类型都有自己私有的[[Class]]属性,而且这个class是不能被任何人修改的,所以tostring方法是检测属性类型最准确的方法,比instanceof还准确。

他也可以细分内置构造函数创建的类对象

通过内置构造函数(Array、Date等)创建的对象包含"类属性"(class attribute),他与构造函数的名称相匹配(这里也是我从contructor.name来区分数据类型的启发点)。

但是,他无法区分自定义对象类型

通过对象直接量和Object.create创建的对象的类属性是"object",那些自定义构造函数创建的对象也是一样。类属性都是"Object",因此对于自定义类来说,没办法通过类属性来区分对象的类。

为什么用call

这里用call是为了改变toString函数内部的this指向,其实也可以用apply

之所以必须改变this指向是因为,toString内部是获取this指向那个对象的[[Class]]属性值的,如果不改变this指向为我们的目标变量,this将永远指向调用toStringprototype

另外也是因为,很多对象继承的toString方法重写了,为了能调用正确的toString,才间接的使用call/apply方法。

代码演示:

javascript 复制代码
js
复制代码
Object.prototype.toString = function () {
  console.log(this);
};
const arr1 = [];
Object.prototype.toString(arr1); // 打印(即this指向) Object.prototype
Object.prototype.toString.call(arr1); // 打印(即this指向) arr1

为什么null也能判断?undefined和null这两个原始值不是没有属性值吗?

因为每一个类型都有自己唯一的特定 类属性 (class attribute) 标识,null也有、undefined也有。

该方法判断类型的缺陷

他虽然判断类型完善,但也不是没有缺点,主要有两点:

  1. tostring会进行装箱操作,产生很多临时对象 (所以真正进行类型转换时建议配合typeof来区分是对象类型还是基本类型,见最后代码)

  2. 他无法区分自定义对象类型 ,用来判断这类对象时,返回的都是Object(针对"自定义类型"可以采用instanceof区分)

总结一下

1. typeof

  • 用于判断原始类型(除 null 外),能识别 number, string, boolean, undefinedfunction
  • 对引用类型(除 function 外)返回 object

2. instanceof

  • 用于判断引用类型。
  • 检查对象是否为某构造函数的实例。
  • 通过原型链查找,无法判断原始类型。

3. Object.prototype.toString.call()

  • 万能方法,可判断所有类型,包括 nullundefined
  • 返回格式 [object Type]
  • 缺点:对自定义对象类型返回 Object,存在临时对象开销。

总结:typeof 用于基本类型和函数,instanceof 用于引用类型,Object.prototype.toString.call() 是最全面的方法。

制作不易,感谢支持

相关推荐
腾讯TNTWeb前端团队6 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰10 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪10 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪10 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy11 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom11 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom11 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom11 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom12 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom12 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试