JavaScript 数据类型检测以及转换

364 阅读5分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

数据类型检测

typeof

typeof 1 // 'number' 
typeof '1' // 'string' 
typeof undefined // 'undefined' 
typeof true // 'boolean' 
typeof Symbol() // 'symbol' 
typeof null // 'object' 
typeof [] // 'object' 
typeof {} // 'object' 
typeof console // 'object' 
typeof console.log // 'function'

我们可以看到,typeof null的返回值是 object,而我们知道 null 是一个基础数据类型,因此在判断一个值是否为 null 的时候,直接使用 ===null 判断即可。

而对于引用类型,除了 function 以外,typeof 是没办法判断真正的数据类型的。

instanceof

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

function Car(model) {
  this.model = model
}
const auto = new Car('mercedes-benz')

console.log(auto instanceof Car)   // true
console.log(auto instanceof Object)  // true

'1' instanceof String  // false

let str = new String('1')
str instanceof String // true

typeofinstanceof 的区别有:

  • instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型;
  • typeof 可以判断基础数据类型(null 除外),但是引用数据类型中,除了 function 类型以外,其他的无法判断。

Object.prototype.toString.call

Object.prototype.toString.call({}) // "[object Object]" 
Object.prototype.toString.call(1) // "[object Number]" 
Object.prototype.toString.call('1') // "[object String]" 
Object.prototype.toString.call(true) // "[object Boolean]" 
Object.prototype.toString.call(function(){}) // "[object Function]" 
Object.prototype.toString.call(null) //"[object Null]" 
Object.prototype.toString.call(undefined) //"[object Undefined]" 
Object.prototype.toString.call(/123/g) //"[object RegExp]" 
Object.prototype.toString.call(new Date()) //"[object Date]" 
Object.prototype.toString.call([]) //"[object Array]" 
Object.prototype.toString.call(document) //"[object HTMLDocument]" 
Object.prototype.toString.call(window) //"[object Window]"

接下来实现一个全局通用的获取数据类型的方法。

function getType(obj){
  let type  = typeof obj;
  if (type !== "object") {    // 先进行typeof判断,如果是基础数据类型,直接返回
    return type;
  }
  // 对于typeof返回结果是object的,再进行如下的判断,正则返回结果
  return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1'); 

}

/* 代码验证,需要注意大小写,哪些是typeof判断,哪些是toString判断?思考下 */
getType([])     // "Array" typeof []是object,因此toString返回
getType('123')  // "string" typeof 直接返回
getType(window) // "Window" toString返回
getType(null)   // "Null"首字母大写,typeof null是object,需toString来判断
getType(undefined)   // "undefined" typeof 直接返回
getType()            // "undefined" typeof 直接返回
getType(function(){}) // "function" typeof能判断,因此首字母小写
getType(/123/g)      //"RegExp" toString返回

通过此方法可以很具体的获取某个数据是什么类型,上述方法在 toString 返回时首字母会大写,若需要统一则需要首字母进行转换。但可以更直观的区分哪些是 typeof 返回的,哪些是 toString 返回的。

数据类型转换

Number() 强制转换规则

  • 布尔值 true → 1 false → 0
  • 数字 → 自身
  • null → 0
  • undefined → NaN
  • 字符串
    • 只包含数字(只包含0X/0x的十六进制) → 十进制数字
    • 有效的浮点格式数字 → 浮点数
    • 空字符串 → 0
    • 不是上述格式 → NaN
  • Symbol → 抛出错误
  • 对象
    • 如果部署了 Symbol.toPrimitive 方法,优先调用再返回;
    • 调用 valueOf(),如果转换为基础类型,则返回;
    • 调用 toString(),如果转换为基础类型,则返回;
    • 如果都没有返回基础类型,会报错。
Number(true)  // 1 
Number(false) // 0 
Number('0111') //111 
Number(null) //0 
Number(undefined) // NaN
Number('') //0 
Number('1a') //NaN 
Number(-0X11) //-17 
Number('0X11') //17

Boolean() 强制类型转换

除了 undefinednullfalse、 ''、 0(包括 +0,-0)、 NaN 转换出来是 false,其他都是 true

Boolean(0) //false 
Boolean(null) //false 
Boolean(undefined) //false 
Boolean('') //false 
Boolean(NaN) //false 
Boolean(1) //true 
Boolean(13) //true 
Boolean('ab') //true

String() 强制类型转换

String(11) //'11'
String(true) //'true'
String(false) //'false'
String(null) //'null'
String(NaN) //'NaN'
String(undefined) //'undefined'
String(+0) //'0'
String(-0) //'0'
String(-111) //'-111'
String(+111) //'111'
String({a:1}) //'[object Object]'

'==' 的隐式类型转换规则

  1. 如果类型相同,无须进行类型转换
  2. 如果其中一个操作值是 null 或者 undefined,那么另一个操作符必须为 null 或者 undefined,才会返回 true,否则都返回 false
  3. 如果其中一个是 Symbol 类型,那么返回 false
  4. 两个操作值如果为 stringnumber 类型,那么就会将字符串转换为 number
  5. 如果一个操作值是 boolean,那么转换成 number
  6. 如果一个操作值为 object 且另一方为 stringnumber 或者 symbol,就会把 object 转为原始类型再进行判断(调用 objectvalueOf/toString 方法进行转换)。
null == undefined // true 规则2 
null == 0 // false 规则2 
'' == null // false 规则2 
'' == 0 // true 规则4 字符串转隐式转换成Number之后再对比 
'123' == 123 // true 规则4 字符串转隐式转换成Number之后再对比 
0 == false // true e规则 布尔型隐式转换成Number之后再对比 
1 == true // true e规则 布尔型隐式转换成Number之后再对比 

var a = { 
    value: 0, 
    valueOf: function() { 
        this.value++; 
        return this.value; 
    } 
}; 
// 注意这里a又可以等于1、2、3 
console.log(a == 1 && a == 2 && a ==3); //true 规则 Object隐式转换 
// 注:但是执行过3遍之后,再重新执行a==3或之前的数字就是false,因为value已经加上去了,这里需要注意一下

'+' 的隐式类型转换规则

  1. 如果其中有一个是字符串,另外一个是 undefinednull 或布尔型,则调用 toString() 方法进行字符串拼接;如果是纯对象、数组、正则等,则默认调用对象的转换方法会存在优先级(下一讲会专门介绍),然后再进行拼接。
  2. 如果其中有一个是数字,另外一个是 undefinednull、布尔型或数字,则会将其转换成数字进行加法运算,对象的情况还是参考上一条规则。
  3. 如果其中一个是字符串、一个是数字,则按照字符串规则进行拼接。
1 + 2 // 3 常规情况 
'1' + '2' // '12' 常规情况 

// 下面看一下特殊情况 
'1' + undefined // "1undefined" 规则1,undefined转换字符串 
'1' + null // "1null" 规则1,null转换字符串 
'1' + true // "1true" 规则1,true转换字符串 
'1' + 1n // '11' 比较特殊字符串和BigInt相加,BigInt转换为字符串 
1 + undefined // NaN 规则2,undefined转换数字相加NaN 
1 + null // 1 规则2,null转换为0 
1 + true // 2 规则2,true转换为1,二者相加为2 
1 + 1n // 错误 不能把BigInt和Number类型直接混合相加 
'1' + 3 // '13' 规则3,字符串拼接

最后说一句

如果这篇文章对您有所帮助,或者有所启发的话,帮忙关注一下,您的支持是我坚持写作最大的动力,多谢支持。