判断JS数据类型的五种方法

JavaScript 中常见的几种数据类型:

目录

JavaScript 中常见的几种数据类型:

一、分类

二、判断

1、typeof

null既然属于基本数据类型,为什么用typeof返回的是object呢?

js小数运算出现的问题(精度丢失)

解决方法一

解决方法二

解决方法三

2、instanceof

3、constructor

细节问题:

4、Object.prototype.toString 

5、===

三、相关问题

1、undefined 与 null的区别

2、什么时候给变量赋值为null呢?

3、严格区分变量类型和数据类型?


一、分类

基本类型:string,number,boolean,symbol(ES6新增)基本类型中也有两个特殊的类型,即:undefined,null

引用类型:Object,Function,Array,RegExp,Date,...

二、判断

1、typeof

typeof 返回一个表示数据类型的字符串,返回结果包括:number、boolean、string、object、undefined、function等6种数据类型

   typeof '123'       string   // 有效
    
   typeof 1           number   // 有效
   
   typeof true        boolean  // 有效
   
   typeof Symbol('1') symbol   // 有效
   
   typeof undefined   undefined // 有效
   
   typeof {a:1,b:2}   object   // 有效
   
   function c(){console.log('123')}
   
   typeof c          function  // 有效

   typeof null        object  // 无效

   typeof  [] ;  //object 无效

   typeof  new  Date();  //object 无效

   typeof  new  RegExp();  //object 无效
    

总结:typeof 可以对JS基础数据类型做出准确的判断,而对于引用类型返回的基本上都是object, 其实返回object也没有错,因为所有对象的原型链最终都指向了Object,Object是所有对象的`祖宗`。 但当我们需要知道某个对象的具体类型时,typeof 就显得有些力不从心了

null既然属于基本数据类型,为什么用typeof返回的是object呢?

js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息?
000:对象
010:浮点数
100:字符串
110:布尔
1:整数
但是对于 undefined 和 null 来说,这两个值的信息存储是有点特殊的。
null:所有机器码均为0
undefined:用 −2^30 整数来表示
所以,typeof 在判断 null 的时候就出现问题了,由于 null 的所有机器码均为0,因此直接被当做了对象来看待。

js小数运算出现的问题(精度丢失)

var num1 = 0.1
var num2 = 0.2
var num3 = num1 + num2
console.log(num3) // 0.30000000000000004

本质原因:计算机对于数据都是转换为二进制存储的,但是对于某些浮点数计算机无法将其精确表达为二进制

像0.5这种数字,可以很快计算得到2进制结果,但是0.1和0.2这样的数字,是永远不可能计算得到准确的2进制结果的,因为一直乘2,就没有得到整数的时候,此时在转换2进制的过程中,会形成无限死循环。

计算机内部在存储无限死循环数据时,必须要有一个限度,采取舍去的原则,所以,0.1和0.2在计算机内部存储的对应的2进制数字,本来就不精准,所以相加得到的2进制结果,也就不精准了,那转换成10进制后,是会有一定的误差的,所以结果不是精准的0.3。

计算机内部对于2进制小数,根据IEEE754标准(是一个仔细制定的表示浮点数及其运算的标准),小数部分最多会保留52位:

所以上面那段代码,在计算机中的运算过程其实是如下所示这样的

0.0001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 
+
0.0001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 
=
0.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011

所以,不精准是正确的,只是偶尔会有两个不精准的数字相加,正好得到一个精准的值。

解决方法一

将需要运算的小数扩大10倍、100倍、。。。将小数扩大到整数,然后进行运行,最后再缩小扩大的倍数。例:

var num1 = 0.1
var num2 = 0.2
var num3 = (num1 * 10 + num2 * 10) / 10
console.log(num3) // 0.3

解决方法二

通过js中Number的内置方法toFixed,强制保留小数点后位数。例:

var num1 = 0.1
var num2 = 0.2
var num3 = num1 + num2
console.log(num3.toFixed(3)) // 0.300 - 强制保留小数点后3位

解决方法三

封装数学运算方法,当需要进行数学运算的时候,不直接进行,而调用自己封装的方法来实现数学运算。

细说JavaScript中小数点计算不精准的原因和解决方案

2、instanceof

instanceof 是用来判断 A 是否为 B 的实例对,表达式为:A instanceof B,如果A是B的实例,则返回true,否则返回false。 在这里需要特别注意的是:instanceof检测的是原型,我们用一段伪代码来模拟其内部执行过程:

instanceof (A,B) = {
     var  L = A.__proto__;
     var  R = B.prototype;
     if (L === R) {
         //A的内部属性__proto__指向B的原型对象
         return  true ;
     }
     return  false ;
}

从上述过程可以看出,当 A 的 __proto__ 指向 B 的 prototype 时,即A的原型链上可以找到B时,就认为A就是B的实例,我们再来看几个例子:

[] instanceof Array;  //true
{} instanceof Object; //true
new  Date() instanceof Date; //true
 
function Person(){};
new  Person() instanceof Person; // true
 
[] instanceof Object;  //true
new  Date() instanceof Object; //true
new  Person instanceof Object; //true

[] 的 __proto__  直接指向Array.prototype, 间接指向Object.prototype, 所以按照 instanceof 的判断规则,[] 就是Object的实例。当然,类似的new Date()、new Person() 也会形成这样一条原型链,因此,instanceof 只能用来判断两个对象是否属于原型链的关系, 而不能获取对象的具体类型。

3、constructor

当一个函数F被定义时,JS引擎会为F添加prototype原型,然后再在prototype上添加一个constructor属性,并让其指向F的引用。如下所示:

当执行 var f = new F() 时,F被当成了构造函数,f是F的实例对象,此时F原型上的constructor传递到了f上,因此f.constructor == F

可以看出,JS在函数F的原型上定义了constructor,当F被当作构造函数用来创建对象时,创建的新对象就被标记为了“F” 类型,使得新对象有名有姓,可以追溯。

同理,JS中的数据类型也遵守这个规则

细节问题:

  • null和undefined是无效的对象,因此是不会有constructor存在的,这两种类型的数据需要通过typeof来判断。
  • JS对象的constructor是不稳定的,这个主要体现在自定义对象上,当开发者重写prototype后,原有的constructor会丢失,constructor会默认为Object

4、Object.prototype.toString 

toString是Object原型对象上的一个方法,该方法默认返回其调用者的具体类型,更严格的讲,是 toString运行时this指向的对象类型, 返回的类型格式为[object,xxx],xxx是具体的数据类型,其中包括:String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument,... 基本上所有对象的类型都可以通过这个方法获取到。 

Object.prototype.toString.call( '' ) ;    // [object String]

Object.prototype.toString.call(1) ;     // [object Number]

Object.prototype.toString.call( true ) ;  // [object Boolean]

Object.prototype.toString.call(undefined) ;  // [object Undefined]

Object.prototype.toString.call( null ) ;  // [object Null]

Object.prototype.toString.call( new  Function()) ;  // [object Function]

Object.prototype.toString.call( new  Date()) ;  // [object Date]

Object.prototype.toString.call([]) ;  // [object Array]

Object.prototype.toString.call( new  RegExp()) ;  // [object RegExp]

Object.prototype.toString.call( new  Error()) ;  // [object Error]

Object.prototype.toString.call(document) ;  // [object HTMLDocument]

Object.prototype.toString.call(window) ;  //[object global] window是全局对象global的引

需要注意的是,必须通过Object.prototype.toString.call来获取,而不能直接 new Date().toString(), 从原型链的角度讲,所有对象的原型链最终都指向了Object, 按照JS变量查找规则,其他对象应该也可以直接访问到Object的toString方法,而事实上,大部分的对象都实现了自身的toString方法,这样就可能会导致Object的toString被终止查找,因此要用call来强制执行Object的toString方法。

5、===

  • 可以判断 undefined,null
var a;
    console.log(a, typeof a, typeof a === 'undefined', a === undefined); // undefined 'undefined' true true
    console.log(undefined === 'undefined'); // false

    a = 3;
    console.log(typeof a === 'number'); // true

    a = 'atguigu';
    console.log(typeof a === 'string'); // true  string小写

    a = true;
    console.log(typeof a === 'boolean'); // true
    
    a = null;
    console.log(typeof a, a === null); // object true

  // 2、对象数据类型
    var b1 = {
        b2:[1, 'abc', console.log],
        b3:function(){
            console.log('b3');
            return function(){
                return 'xfzhang';
            }
        }
    };

    // 判断是否是函数还有一种方式
    console.log(typeof b1.b3 === 'function'); // true
    

三、相关问题

实例:实例对象
类型:类型对象

1、undefined 与 null的区别

undefined 代表定义未赋值
null 代表定义并赋值了,只是值为null

2、什么时候给变量赋值为null呢?

初始赋值,表明将要赋值为对象
结束前,让对象称为垃圾对象(被垃圾回收器回收)

3、严格区分变量类型和数据类型?

数据的类型:① 基本类型 ② 对象类型(一般对象类型就是引用类型)
变量的类型(变量内存值的类型): ① 基本类型:保存的就是基本类型的数据 ② 引用类型:保存的是地址值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值