js数据类型

155 阅读5分钟

数据类型概念

JavaScript分为基本数据类型和引用数据类型。

基本数据类型:

  • Undefined
  • Null
  • String
  • Number
  • Boolean
  • bigInt
  • Symbol

引用数据类型:

  • Object
    • Function
    • Date
    • Math
    • RegExp
    • Array

不同的数据类型会存放在不同的内存中。

  1. 基础类型存储在栈内存(Stack)中,被引用或者拷贝时,会创建一个完全相等的变量。
  2. 引用数据类型存储在堆内存(Heap)中,然后在栈内存中存储变量的堆内存地址,当多个引用指向同一个地址时,实际上指向的是同一个堆内存。

注:由于 Math 本身就是一个object,并没有Math这种类型,下面类型判断中不会检测Math。

类型检测

因为 JavaScript类型系统是松散的,所以需要一种手段来确认任意变量的数据类型。

typeof

console.log(typeof undefined);  // undefined
console.log(typeof null);       // object
console.log(typeof '213');      // string
console.log(typeof 213);        // number
console.log(typeof false);      // boolean
console.log(typeof BigInt(213)) // bigint
console.log(typeof Symbol(12)); // symbol
console.log(typeof {});         // object
console.log(typeof function() {});    // function
console.log(typeof new RegExp(/\s/)); // object
console.log(typeof []);         // object

可以发现使用 typeof 会存在很多问题:

  1. 基础数据类型中检测 null 有误,没有正确返回 null,而是返回 object。
  2. 引用数据类型中只能检测 object 和 function 数据类型,其他的都只能返回 object。

instanceof

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

console.log(undefined instanceof undefined);        // 报错
console.log(null instanceof null);                  // 报错
console.log(new Number(123) instanceof Number);     // true
console.log(new String('123') instanceof String);   // true
console.log(new Boolean(true) instanceof Boolean);  // true
console.log(Symbol(12) instanceof Symbol);          // false
console.log(BigInt(1234) instanceof BigInt)         // false
console.log({} instanceof Object);                  // true
console.log(function() {} instanceof Function);     // true
console.log(new RegExp(/\s/) instanceof RegExp);    // true
console.log([] instanceof Array);                   // true

运行之后可以发现instanceof还是会存在不少问题:

  1. 由于undefined、null、Symbol、BigInt、不是构造函数,无法被 new,所以也就无法在其 prototype 上查找是凑是现在该实例的原型对象

constructor

constructor 与 instanceof 非常相似,但是 constructor 检测与 instanceof 不一样,还可以处理基本数据类型。

console.log(("1").constructor === String);                // true
console.log((1).constructor === Number);                  // true
console.log((false).constructor === Boolean);             // true
console.log((Symbol(123)).constructor === Symbol);        // true
console.log((BigInt(23)).constructor === BigInt);         // true
// console.log((null).constructor === null); 
// console.log((undefined).constructor === undefined); 
console.log(({}).constructor === Object);                 // true
console.log((function(){}).constructor === Function);     // true 
console.log((new Date()).constructor === Date);           // true
console.log((new RegExp(/\s/)).constructor === RegExp);   // true 
console.log([].constructor === Array);                    // true

缺点:

  1. 因为null和undefined是无效的对象,因此是不会有constructor存在的。
  2. 函数的 constructor 是不稳定的,这个主要体现在把类的原型进行重写,重写之后类型判断就会出现问题。

Object.prototypf.toString.call()

这也是我们最推荐的方法,使用此方法无论什么数据类型都能正确返回

toString 是 Object 原型上的方法,调用该方法统一返回“[object Xxxx]”的字符串,其中Xxx就是调用者的数据类型(首字母大写)。

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]"

数据类型转换

将值从一种数据类型转换为另一种数据类型叫做类型转换。在日常的业务开发中,经常遇到JavaScript数据类型转换的问题,有的时候需要我们主动强制转换,而有的时候JavaScript会进行隐式转换。

强类型转换

  1. toString
原始值转换结果
undefined'undefined'
Boolean'true' / 'false'
Number对应的字符串类型
SymbolUncaught TypeError: can't convert symbol to string
Object先调用 toPrimitive。再调用 toNumber
  1. toNumber
原始值转换结果
undefinedNaN
null0
true1
false0
string根据语法和转换规则来转换
SymbolUncaught TypeError: can't convert symbol to number
Object先调用 toPrimitive。再调用 toNumber

注:toPrimitive 会先检查该值是否有 valueOf 方法,如果有就返回基本数据类型值,如果没有就是用 toString 的返回值来进行强制类型转换。

String 转 Number 类型规则:

  • 如果字符串中只包含数字,那么就转换成对应的数字
  • 如果字符串只包含十六进制格式,那么就转换为对应的十进制数字。
  • 如果字符串为空,那么转换为0。
  • 如果字符串包含上述之外的字符串,那么转为NaN。
  1. toBoolean
原始值转换结果
undefinedfalse
number0和NaN为false,其他都为true
Symboltrue
Objecttrue

隐式类型转换

隐式类型转换一般是在涉及到运算符的时候才会出现的情况。

  1. “==” 的隐式类型转换规则
  • 如果类型相同,无需进行转换。
  • 如果其中一个操作值是null或者undefined,那么另一个操作符必须是null或者undefined,才会返回true,否则都返回false。
  • 如果其中一个是Symbol类型,那么返回false
  • 两个操作符如果是string和nunber类型,那么就会将字符串转换为number
  • 如果一个操作符是boolean,那么转换为number
  • 如果一个操作值为object且另一方为string、number或者symbol,就会把object类型转为原始数据类型在判断
  1. “+” 的隐式转换类型
  • 如果其中一个是字符串,另外一个是 undefined、null或者boolean,则调用toString方法进行字符串拼接
  • 如果一个是数字,另一个是undefined、null、布尔值或者数字,则会将其转换为数字进行加法运算
  • 如果其中一个是字符串、一个是数字,则按照字符串规则进行拼接。