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() 是最全面的方法。

制作不易,感谢支持

相关推荐
m0_7482309415 分钟前
Rust赋能前端: 纯血前端将 Table 导出 Excel
前端·rust·excel
qq_5895681023 分钟前
Echarts的高级使用,动画,交互api
前端·javascript·echarts
黑客老陈1 小时前
新手小白如何挖掘cnvd通用漏洞之存储xss漏洞(利用xss钓鱼)
运维·服务器·前端·网络·安全·web3·xss
正小安1 小时前
Vite系列课程 | 11. Vite 配置文件中 CSS 配置(Modules 模块化篇)
前端·vite
暴富的Tdy2 小时前
【CryptoJS库AES加密】
前端·javascript·vue.js
neeef_se2 小时前
Vue中使用a标签下载静态资源文件(比如excel、pdf等),纯前端操作
前端·vue.js·excel
m0_748235612 小时前
web 渗透学习指南——初学者防入狱篇
前端
z千鑫2 小时前
【前端】入门指南:Vue中使用Node.js进行数据库CRUD操作的详细步骤
前端·vue.js·node.js