js的数据类型、类型判断、类型转换,让你顿悟升华

3,217 阅读9分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

JS的数据类型、类型判断以及类型转换

Tips:本文是将代码放在浏览器Console下执行

JS的数据类型

JS的数据类型分为以下两类:

  1. 基本(原始)类型:String Number Boolean Null Undefined Symbol BigInt
  2. 引用(对象)类型:Object Array Date Function RegExp 基本包装类型

基本类型和引用类型的区别

  1. 存储值的位置不一样(这一条很重要,有助于理解深浅拷贝),原始类型:栈内存,对象类型:堆内存(但是引用地址还是在栈内存上)

  2. 原始类型是不能携带属性和方法的

    这句话没有错,但是小伙伴们肯定遇到过下面的代码

这张图中s是String类型,是基本类型,那为什么它可以s.length呢,打印出来还是3。这是为什么呢?我们那下面这个代码来说明:

s是个字符串,往他身上挂一个属性a,值为1,但打印出来是undefined,s.length打印出来是3,这是因为let s = '123' //let s = new String(123),构造函数被new了一定会返回一个对象,所以s被称为字符串对象,字符串被创建出来的时候 ,会返回字符串对象,所以可以具备方法和属性,但是被计算机再去访问的时候,会发现他是一个基本类型,会自动执行delete,把它删掉,所以就访问不到了,打印s.a的时候是undefined,而不是报错;而对于打印s.length的时候,只能说不会报错,而不是说s身上真的有这个方法。

JS的类型判断方式

1. Object.prototype.toString.call() 方法,这个方法可以判断任何的类型,返回的是一个字符串

如上图,返回的是一个'[object String]'字符串,如果我们想要获取到后面指定的部分String的话,可以使用字符串的slice方法,我们可以自己编写一个函数,名为myflag,让该函数接受一个参数target

function myflag(target){
   return Object.prototype.toString.call(target).slice(8,Object.prototype.toString.call(target).length-1)
}

然后我们调用该函数,给它传一个值

let a = true
myflag(a)

这样,就能得到变量类型的字符串,如下图返回'Boolean'

2. typeof() 方法,这个方法用来准确判断基本类型(除了null),返回的也是一个字符串

如上图举例,返回的是变量类型的字符串,但是typeof判断null会发生什么呢?

正如大家所见,打印的会是字符串'object',因为电脑是识别二进制,因为null转换为二进制时全是000000···,又因为object二进制是以000开头,所以000开头的会被计算机判定为object,null也就阴差阳错的被判定成object类型了。

此外如果用typeof判断引用类型(对象,数组,正则等)都会返回'object',而函数Function则会返回'function',

所以,typeof不能准确的判断引用类型。

3. instanceof() 方法,这个方法用来判断对象类型,返回一个布尔值,如果判断基本类型,那么会输出false

如上图所示,是在浏览器中打印的instanceof的用法和返回结果,那么为什么instanceof只能判断引用类型呢?

这与instanceof的实现原理有关,instanceof 的原理是通过判断对象的原型中是否能找到类型的prototype,找到了就返回true,找不到就返回false

那么我们模拟手写一个instanceof,看看instanceof里面到底干了什么,首先定义一个函数,取名instance_of(这是我们自己定义的函数,取名随便,这里方便理解),根据instanceof的语法,他有左右两个值,左边是实例对象,右边是类型,所以给我们自己定义的函数两个形参,left,right,剩下的代码如下:

function instance_of(left,right){
  let prototype = right.prototype
  let __proto__  = left.__proto__

  while(true){
    if(__proto__ === null){
      return false
    }
    if(__proto__ === prototype){
      return true
    }
    __proto__ = __proto__.__proto__
  }
}

我们定义一个变量prototype赋值为right(即判断的类型)的prototype,另一个变量__proto__赋值为left(实例对象)的__proto__。他会根据实例对象的隐式原型__proto__,一直循环往上追溯,直到符合两个if判断中的一个,最后通过实例对象的隐式原型等于构造函数的显示原型的原理来判断返回true或者false。如果有不懂的小伙伴,可以先去学习一下原型链的知识,再来理解。那么接下来看一下实现的效果。

这就是instanceof 的判断方法和原理

4. 特定的判断方法

1.数组的isArray() 方法,判断是否为数组,返回true或者false.

2.isNaN() 方法,在 JavaScript 中,NaN 是一个不合法的数字。 Number.isNaN () 方法用于判断传递的值是否为 NaN,并且检查其类型是否为 Number,如果值为 NaN 且类型为 Number,则返回 true,否则返回 false。 在isNaN方法中,它会先将判定的对象调用ToNumber()方法转成数字,ToNumber()方法返回的值如果是NaN,则返回true,否则为false。看如下例子:

第一个例子Number(true)返回的值为1(原因看后文的类型转换),1是数字类型,但值不为NaN,所以isNaN返回的是false,第二个例子Number('123')返回的值为123,123是数字类型,但值不为NaN,所以isNaN返回的是false,第三个例子,Number('1+')返回的值为NaN,NaN是数字类型,且值为NaN,所以isNaN返回的是true。根据这个规则,小伙伴们可以去尝试isNaN对其它类型的判定。

JS的类型转换

JS的类型转换分为显示类型转换和隐式类型转换

1. 显示类型转换:人为的通过类型转换api实现类型转换

显示类型转换比较简单,只需要记就行了,通过 JS 提供的一些函数,可以直接进行转换

  • 转化为 Number 类型:Number() / parseFloat() / parseInt()
  • 转化为 String 类型:String() / toString()
  • 转化为 Boolean 类型: Boolean()

在强制类型转换中,以下几点需要注意:

  • 转布尔值:undefined、null、false、+0、-0、NaN、""  只有这些 Boolean()  是 false ,其余都为 true
  • 转数字:undefined=>NaN Symbol类型转换会报错 null=>0 ,字符串转数字取决于字符串内的内容,如果是数字或者进制数,就正常转,否则就NaN
  • js中对象转字符串经过了如下步骤:
    1. 如果对象具有toString()方法,则调用这个方法。如果它返回一个基本类型值,js将这个值转换为字符串,并返回这个字符串。
    2. 如果对象没有toString()方法,或者这个方法返回的不是一个基本类型值,那么js将调用valueOf()方法。如果存在这个方法,则调用,如果返回值是基本类型值,转换为字符串并返回
    3. 否则,js无法从toString()或valueOf()获得一个基本类型值,此时将会抛出类型错误异常

2. Toprimitive方法:

Toprimitive(v,PreferredType?)

v是要转换的值, PreferredType 是可选参数,ToPrimitive 运算符把其值参数转换为非对象类型。如果对象有能力被转换为不止一种原语类型(接受参数 number 或者string ),可以使用可选的 PreferredType 来选择类型。 在执行ToPrimitive() 时如果第二个参数为空并且 v 为 Date 的事例时,此时preferredType 会被设置为String,其他情况下preferredType都会被设置为 Number

如果 preferredType 为 Number,ToPrimitive执行过程如下:

  1. 如果data为原始值,直接返回;
  2. 否则调用 data.valueOf(),如果执行结果是原始值,返回之;
  3. 否则调用 data.toString(),如果执行结果是原始值,返回之;
  4. 否则报错。

如果 preferredType 为String,将上面的第2步和第3步调换,(类似上文中对象转字符串)即:

  1. 如果data为原始值,直接返回;
  2. 否则调用 data.toString(),如果执行结果是原始值,返回之;
  3. 否则调用 data.valueOf(),如果执行结果是原始值,返回之;
  4. 否则报错。

3. 隐式类型转换: 在某些运算符执行时,因为类型不同无法进行运算,js引擎会自动将其类型转换之后在进行运算(非人为的)

  • 一元操作符

    会默认调用 ToNumber 方法,具体结果看上文中的显示类型转换表

  • 二元操作符

    设左边操作数为v1,右边操作数为v2

    1. v1 = Toprimitive(v1) , v2 = Toprimitive(v2)
    2. 如果v1是字符串或者v2是字符串,那么返回ToString(v1)和ToString(v2)的拼接
    3. 如果第2步不成立就会返回ToNumber(v1)和ToNumber(v2) 的运算结果
null + 1//1

1 + true //2

new Date(2022,05,20)+1//'Mon Jun 20 2022 00:00:00 GMT+0800 (中国标准时间)1'

true == '2' //不相等返回false
  • ==

    x == y 如果x和y是同一基本类型

    1. x是undefined ,返回true
    2. x是null ,返回true
    3. 其它相同基本类型,内容相等返回true,内容不相等则返回false
    4. 如果x是对象,y是字符串或者数字,ToPrimitive(x)== y
[] == 0//true,过程如下
[].valueOf()//[]
[].toString()//''
'' == 0 //true
  • 布尔值和其他类型

    1. 当一方出现布尔值时,另一方一定会进行ToNumber()
[] == ![]//true,过程如下
//!的优先级更高会将右边先转换成布尔类型,因为[]转布尔为true,故![]就是false,即变成了 
[] == false
//此时左边的[]会进行ToNumber(),得到0,即变成
0 == false //故为true

到此为止,根据如上规则,大家可以多去看看典型的类型转换问题,注意每一步所符合的规则判定,细心运算,希望本文对你有所帮助,让你了解到更多知识点,如果有错误的地方还请在评论区指出,一定加以修改,码字不易,留个赞吧~~~