JS 数据类型

244 阅读2分钟

数据类型

数字(number)、字符串(string)、布尔(bool)、符号(symbol)、空(undefined)、空(null)、对象(object)、bigint

  • number 数字
  • string 字符串
  • boolean 布尔
  • symbol 符号
  • bigint 长整型
  • undefined
  • null
  • object 对象
    • array 数组
    • function 函数
    • DateError等等

有以下几个需要注意的点:

  • 数据类型只有 8 种哦,其中 object 也被叫做引用类型或者对象类型,arrayfunction 是对象的子类型(当然还有 DateError等等都是)
  • stringnumberbooleannullundefined 统称为原始类型(Primitive),表示不能再细分下去的基本类型;
  • symbol 是 ES6 中新增的数据类型,表示独一无二的值,通过 Symbol 函数调用生成,由于生成的 symbol 值为原始类型,所以 Symbol 函数不能使用 new 调用
  • nullundefined 通常被认为是特殊值,这两种类型的值唯一,就是其本身

因为 bigint 为 ES11 中新增的数据类型,使用较少,并且没有明显的特殊性(类型判断时没有“坑”),所以这里将其忽略

类型判断

  • typeof
  • instanceof
  • Object.prototype.toString()

typeof


typeof 'seymoe'    // 'string'
typeof true        // 'boolean'
typeof 10          // 'number'
typeof Symbol()    // 'symbol'
typeof null        // 'object'
typeof undefined   // 'undefined'

typeof {}           // 'object'
typeof []           // 'object'
typeof(() => {})    // 'function'

可以看到 typeof 有以下几个问题

  • null 得到的结果为 'object'
  • 除了 function,其他引用类型都会返回 'object'

instanceof

通过 instanceof 可以判断该实例是否是由某个类实例化而来,其原理就是测试构造函数的 prototype 是否出现在被检测对象的原型链上。

const num1 = new Number(1);
const num2 = Number(1);
const num3 = 1;
console.log(num1 instanceof Number); // true
console.log(num1 instanceof Object); // true
console.log(num2 instanceof Number); // false
console.log(num3 instanceof Number); // false

const arr = [];
const obj = {};
console.log(arr instanceof Array);    // true
console.log(arr instanceof Object);   // true
console.log(obj instanceof Object);   // true

可以看到,有几个问题:

  • 对原始类型使用 instanceof,不管匹配的是啥,都是 false
  • Number其实是包装对象,继承于 Object,所以由其 new 出来的实例,num1 instanceof Objecttrue
  • Array 是由 Object 继承而来的,所以 arr.__proto__.__proto__ === Object.prototypetrue(同理,function 也跟 array 是一样的)
  • 对象的 __proto__ 是可以自己改,譬如 arr.__proto__ = Error.prototype,改了之后再用 instanceof 就彻底乱套了

instanceof 的底层实现原理如下:

/**
 * 通过判断 current 的 __proto__ 链条上是否与 target.prototype 匹配
 **/
function myInstanceof(current, target) {
  const current = current.__proto__;
  while (true) {
    if (current === null) {
      return false;
    }
    if (current === target.prototype) {
      return true;
    }
    current = current.__proto__;
  }
}
class ClassA {}
const a = new ClassA();
console.log(a.__proto__ === ClassA.prototype); // true
console.log(a instanceof ClassA); // true

class ClassB extends ClassA {}
const b = new ClassB();
console.log(b.__proto__ === ClassB.prototype); // true
console.log(b.__proto__.__proto__ === ClassA.prototype); // true
console.log(b instanceof ClassB); // true
console.log(b instanceof ClassA); // true

Object.prototype.toString()

Object.prototype.toString() 可以说是判定 JavaScript 中数据类型的终极解决方法了

Object.prototype.toString.call({})              // '[object Object]'
Object.prototype.toString.call([])              // '[object Array]'
Object.prototype.toString.call(() => {})        // '[object Function]'
Object.prototype.toString.call('seymoe')        // '[object String]'
Object.prototype.toString.call(1)               // '[object Number]'
Object.prototype.toString.call(true)            // '[object Boolean]'
Object.prototype.toString.call(Symbol())        // '[object Symbol]'
Object.prototype.toString.call(null)            // '[object Null]'
Object.prototype.toString.call(undefined)       // '[object Undefined]'

Object.prototype.toString.call(new Date())      // '[object Date]'
Object.prototype.toString.call(Math)            // '[object Math]'
Object.prototype.toString.call(new Set())       // '[object Set]'
Object.prototype.toString.call(new WeakSet())   // '[object WeakSet]'
Object.prototype.toString.call(new Map())       // '[object Map]'
Object.prototype.toString.call(new WeakMap())   // '[object WeakMap]'