JavaScript--- 数据类型、类型检测

219 阅读6分钟

基本数据类型

Null、 Undefined 、String、 Number、 Boolean、 Symbol(唯一值)、 bigInt(大数据类型)

原始数据类型:直接存储在栈中,占据空间小、大小固定、频繁使用的数据。

引用数据类型

Object、Array、Function、Date和正则、Map、Set等

引用数据类型存储在堆(heap)内存中,并且变量本身存储在栈内存中,但是栈中的这个变量存储的并不是实际的数据值,而是一个指向堆内存中实际对象所在位置的指针(或引用)。

引用数据类型:保存在内存中的对象(同时保存在栈内存和堆内存中),占据空间大、大小不固定。在栈中存储指针,该指针指向堆中该实体的起始地址。解释器寻找引用值时,首先检索其在栈中的地址,取得地址后从堆中获得实体。

存储的区别:[基栈、引堆]

  • 基本数据类型直接存储在中,数据大小确定,内存空间大小可以分配,按值传递,值不可变,可以重新赋值。
  • 引用数据类型存放在中,变量实际是一个存放在栈内存的指针,指针指向堆内存中的地址,每个空间大小不一样。按引用传递

null与undefined的区别

  • null:表示一个值被定义了,定义为空值。
// 使用场景
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
  • undefined:表示根本不存在定义。
// 使用场景
(1)变量声明但未赋值
    let x
    console.log(x)// undefined
(2)函数没有return值时
    function test(){}
    console.log(test()) // undefined
(3)访问对象中不存在的属性
    let obj = {}
    console.log(obj.name) // undefined
   
  • 检测
null == undefined     // true
null === undefined    // false

typeof undefined      // undefined
typeof null           // object

检测数据类型得几种方法

typeof (只能判断js的基本数据类型,无法判断数组、null、对象)支持两种语法形式:

//   作为运算符:typeof x
//   函数形式:typeof(x)
//   特殊情况:typeof null ---->objectnull的二进制表示为全零(即00000000),与对象类型标签相同。所以typeof null 错误识别为“object”】

image.png

总结:

- 对于基本类型,除null以外,均可以返回正确的结果(typeof null --->object)
- 对于引用类型,除function以外,一律返回object类型
- 对于null,返回object类型.在js中,如果二进制前三位都为0,就会被`typeof`判断为object。
其中null的二进制全是0,故返回值为object。
- 对于function返回function类型

instanceof

用于检测构造函数的prototype属性是否出现在某个实例对象原型链上

console.log(bool instanceof Boolean);// false
console.log(num instanceof Number);// false
console.log(str instanceof String);// false
console.log(und instanceof Object);// false
console.log(null instanceof Object);// false
console.log(arr instanceof Array);// true
console.log(obj instanceof Object);// true
console.log(fun instanceof Function);// true

var bool2 = new Boolean()
console.log(bool2 instanceof Boolean);// true

var num2 = new Number()
console.log(num2 instanceof Number);// true

var str2 = new String()
console.log(str2 instanceof String);//  true

instanceof的原理

检测constructor.prototype是否存在于参数object的原型链上。instanceof查找的过程中遍历object的原型链,直到找到constructor的prototype,如果查找失败,则返回false,成功则返回true。

function myInstanceof(obj,constructor){
 // 检查obj是否为null或undefined
 if(obj === null || typeof obj !== 'object'){
   return false
 }
  // 获取对象的原型
  let proto = Object.getPrototypeOf(obj)
  // 循环检查原型链
  while(proto !== null){
   if(proto == constructor.prototype){
    return true  //找到匹配的原型,返回true
   }
   proto = Object.getPrototypeOf(proto) // 继续向上查找原型链
  }
  return false; // 原型链中没有找到匹配的构造函数原型,返回false
}

// 示例使用
console.log(myInstanceof({},Object)) // true

判断构造函数(constructor)

构造函数原型上由一个constructor属性指向构造函数自身的。如果在实例上使用constructor时,就会直接使用其构造函数原型的上的该属性,并指向其构造函数。

    console.log([].constructor === Array); // true
    console.log({}.constructor === Object); // true

使用Object.prototype.toString.call()函数

原理:
  • “根”原型(Object.prototype)下,有个toString的方法,记录着所有 数据类型(构造函数)
  • .call作用是改this指向。让传入的对象,执行 “根”原型的toString方法

首先,取得对象的一个内部属性[[class]],依据这个属性,返回一个类似于'[object Array]'的字符串作为结果。利用这个方法,在配合call,可以取得任何对象的内部属性[[Class]],然后将类型检测转化为字符串比较。

call()方法可以改变this的指向,Object.prototype.toString最终会返回形式如[object,class]的字符串,class指代的时其检测出的数据类型。

console.log(Object.prototype.toString.call(boolean));//[object Boolean]
console.log(Object.prototype.toString.call(number));//[object Number]
console.log(Object.prototype.toString.call(string));//[object String]
console.log(Object.prototype.toString.call(undefined));//[object Undefined]
console.log(Object.prototype.toString.call(null));//[object Null]
console.log(Object.prototype.toString.call(array));//[object Array]
console.log(Object.prototype.toString.call(object));//[object Object]
console.log(Object.prototype.toString.call(Function));//[object Function]


// 去除掉返回值中的object
console.log(Object.prototype.toString.call(Function).slice(8,-1));// Function

slice(startIndex,endIndex),从0开始索引,其中8代表从第8位(包含)开始截取(本例中代表空格后面的位置),-1代表截取到倒数第一位(不含),所以正好截取到[object String]中的String。

  • 最好的数据类型检测方法
function type(obj){
   return typeof obj !== "object" ? typeof obj :Object.prototype.toString.call(obj).slice(8,-1).toLowerCase();
}

typeof、instanceof的区别

  • typeof用于基本数据类型的类型判断,无法甄别对象具体类型
  • instanceof用于对象的类型判断,基于原型链上的继承关系

额外补充点(JS中的强制转换规则)

  • Number()强制转换
    • 布尔值,true转换为1,false转换为0
    • 数字返回自身
    • null返回0
    • undefined返回NaN
    • 字符串转换
      • 空字符串,转换为0
      • 字符串中只包含数字(Ox/0X开头数字可以有正负),将其转换为十进制
      • 字符串中包含有效的浮点格式,转换为浮点数
      • 以上都不是,返回NaN
    • 如果是Symbol,抛出错误
Number(true) //  1
Number(false) //  0
Number('0111') //  111
Number(null) //  0
Number('') //  0
Number('1a') //  NaN
Number(-0X11) //  -17
Number('0X11') //  17
  • Boolean()方法的强制转换规则 undefined,null,false,'',0(+0,-0),NaN转换为false,其他转换为true。
Boolean(0)   // false
Boolean(null)   // false
Boolean(undefined)   // false
Boolean(NaN)   // false
Boolean(1)   // true
Boolean(12)   // true
Boolean('a')   // true
  • 什么时候自动转换为string类型

    • 在没有对象的前提下 字符串的自动转换,主要发生在字符串的加法运算时。当一个值为字符串,另一个值为非字符串,则后者转为字符串
    '2' +  1   // '21'
    '2' +  true   // '2true'
    '2' +  false   // '2false'
    '2' +  null   // '2null'
    '2' +  undefined   // '2undefined'
    
    • 当有对象且与对象+时候
    // toString对象
    var obj = {
        toString:function(){
          return 'a'
        }
    }
    console.log('2' + obj) // 2a
    
    //常规对象
    var obj = {
       a:1,
       b:2
    }
    console.log('2' + obj) //2[object object]
    
    // 几种特殊对象2’ + {} // '2[object object]'
    '2' + [] // '2'
    '2' + function(){}  // '2fuction(){}'
    '2' + ['koala',1]   // 2koala,1
    
    • string类型转换时,易出错点
    var obj = {
       width:'200'
    }
    obj.width + 20 // 20020
    
  • 什么时候自动转换为Number类型

    • 有加法运算符,但无String类型时,会优先转换为Number类型
    true + 0   // 1
    true + true //2
    true + false // 1