JavaScript的数据类型与判断

189 阅读3分钟

一 JavaScript数据类型

基本类型

  • Number
  • String
  • Boolean
  • undefined
  • null
  • Object
  • Bigint
  • Symbol 引用类型 Function, Object ,Array

二 如何判断JavaScript的数据类型

JavaScript是一门动态类型的语音,一个变量从声明到最后使用,中间经理了很多函数对象,最终的数据类型也会发生变化,所以掌握判断数据类型的方法就显得尤为重要。

第一种的方法 typeof

   typeof undefined //"undefined" 
   typeof null // "object" 
   typeof 1     // "number"
   typeof "1" // "string"
   typeof Symbol() // "symbol"
   typeof function() {} // "function" 
   typeof {} // "object"
   typeof Number(1) // "number"
   typeof String("1") // "string"
   typeof new Number(1) // "object" typeof new String(1) // "object"
注意点1:typeof 不能识别null 如何识别null
 可以直接使用===运算符来判断或者使用Object.prototype.toString
注意点2:typeof作用于未定义的变量会报错吗
 不会报错会返回undefined
注意点3:typeof Number(1)和typeof String("a") 会返回什么
 会返回numberstring,
 原因:因为NumberString作为普通函数调用的时候,
 是吧参数转化为相应的原始数据类型,也就类似于做一个
 强制类型转化的操作而不是默认当做构造函数

从上面看出对于返回值是object的,有三情况

  • 1:null
  • 2:object
  • 3:array

所以可以发现typeof可以判断基本数据类型,但是难以判断除了函数以外的复杂类型

第二种的方法 instanceof

    3 instanceof Number // false
    '3' instanceof String // false 
    true instanceof Boolean // fals
    instanceof 可以用来判断对象的类型:
    var date = new Date() 
    date instanceof Date // true 
    var number = new Number() 
    number instanceof Number // true
    var string = new String() 
    string instanceof String // true
    const obj = {}
    const arr = []
    obj instanceof Object // true
    arr instanceof Object // true 
    arr instanceof Array // true

instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false,所以instanceof是通过原型链来判断的,但是对于对象来说,Array也会被转换成Object,所以是没办法区分字符串类型和字符串对象类型布尔类型和布尔对象类型数字类型和数字对象类型,同时instanceof 的结果并不一定是可靠的,因为在 ECMAScript7 规范中可以通 过自定义 Symbol.hasInstance 方法来覆盖默认行为。

第三种方法 Object.prototype.toString.call()

对于 Object.prototype.toString() 方法,会返回一个形如 "[object XXX]" 的字符串。 如果对象的 toString() 方法未被重写,就会返回如下面形式的字符串。但是,大多数对象,toString() 方法都是重写了的,这时,需要用 call() 或 Reflect.apply() 等方法来调用。 对于 Object.prototype.toString.call(arg),若参数为 null 或 undefined,直接返回结果。

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

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

若参数不为 null 或 undefined,则将参数转为对象,再作判断。

对于原始类型,转为对象的方法即装箱。转为对象后,取得该对象的 [Symbol.toStringTag] 属性值(可能会遍历原型链)作为 tag,如无该属性,或该属性值不为字符串类型,则依下表取得 tag, 然后返回 "[object " + tag + "]" 形式的字符串。

// Boolean 类型,tag 为 "Boolean"
Object.prototype.toString.call(true);            // => "[object Boolean]"

// Number 类型,tag 为 "Number"
Object.prototype.toString.call(1);               // => "[object Boolean]"

// String 类型,tag 为 "String"
Object.prototype.toString.call("");              // => "[object String]"

// Array 类型,tag 为 "String"
Object.prototype.toString.call([]);              // => "[object Array]"

// Arguments 类型,tag 为 "Arguments"
Object.prototype.toString.call((function() {
  return arguments;
})());                                           // => "[object Arguments]"

// Function 类型, tag 为 "Function"
Object.prototype.toString.call(function(){});    // => "[object Function]"

// Error 类型(包含子类型),tag 为 "Error"
Object.prototype.toString.call(new Error());     // => "[object Error]"

// RegExp 类型,tag 为 "RegExp"
Object.prototype.toString.call(/\d+/);           // => "[object RegExp]"

// Date 类型,tag 为 "Date"
Object.prototype.toString.call(new Date());      // => "[object Date]"

// 其他类型,tag 为 "Object"
Object.prototype.toString.call(new class {});    // => "[object Object]"

下面为部署了 Symbol.toStringTag 的例子。可以看出,属性值期望是一个字符串,否则会被忽略。

var o1 = { [Symbol.toStringTag]: "A" };
var o2 = { [Symbol.toStringTag]: null };

Object.prototype.toString.call(o1);      // => "[object A]"
Object.prototype.toString.call(o2);      // => "[object Object]"

Symbol.toStringTag 也可以部署在原型链上:

class A {}
A.prototype[Symbol.toStringTag] = "A";
Object.prototype.toString.call(new A());   // => "[object A]"

总结:

  • 基本数据类型可以用 typeof 来判断,要注意的是 typeof null 为 "object" 的情况。

  • instanceof 只能用来判断引用数据类型,基本数据类型不可以。缺点是原型链指向改动的话,这个的判断就可能会出错。

  • Object.prototype.toString 适合判断任意类型数据。