数据类型 | 检验数据类型的方法(含手写)

检验数据类型的方法有:

  • typeof
  • instanceof
  • constructor
  • Object.prototype.toString.call()
  • 手写

typeof

typeof 的原理:JavaScript最初版本以32为的单位存储,包括一个小型类型标记(1-3)位和值的实际数据

  • 000:object,表示这个数据是一个对象的引用
  • 1:int,表示这个数据是一个31位的有符号整型
  • 010:double,表示这个数据是一个双精度浮点数的引用
  • 100:string,表示这个数据是一个字符串的引用
  • 110:boolean,表示这个数据是一个布尔值

因为Array和null前三位都是000,所以typeof检测为‘object’

1
2
3
4
5
6
7
8
console.log(typeof 'hello');  // string
console.log(typeof 123); // number
console.log(typeof true); // boolean
console.log(typeof undefined); // undefined
console.log(typeof null); // object (检测错误)
console.log(typeof [1,2,3]); // object (检测错误)
console.log(typeof {name: 'Katrina'}); // object
console.log(typeof function(){}); // function

数组、对象、null都会被判断为object,因此typeof方法有其弊端

instanceof

instanceof原理:用于检测构造函数的原型是否存在于实例对象的原型链上

注意:instanceof只能用于检测引用数据类型,如果是检测基本数据类型,直接返回false

1
2
3
4
5
6
7
console.log(2 instanceof Number);                    // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false

console.log([] instanceof Array); // true
console.log(function(){} instanceof Function); // true
console.log({} instanceof Object); // true

手写instanceof

constructor

constructor原理:实例对象通过constructor对象判断构造函数类型

1
2
console.log([].constructor === Array);   // true
console.log({}.constructor === Array); // false

注意:如果创建一个对象改变了原型,constructor就不能用来判断数据类型

1
2
3
4
5
6
7
8
function Fn() {};

Fn.prototype = new Array();

let f = new Fn();

console.log(f.constructor === Fn); // false
console.log(f.constructor === Array); // true

Object.prototype.toString.call()

Object.prototype.toString原理:当toString被调用的时候会执行以下操作:

  1. 获取this对象的[[Class]]属性的值([[Class]]是一个内部属性,表明了对象的类型)
  2. 计算出三个字符串 “object” , 第一步的属性值,以及 “]” 三部分连接的新字符串
  3. 返回第二步的结果
1
2
3
4
5
6
7
8
9
10
11
console.log(Object.prototype.toString.call(2));   // [object Number]
console.log(Object.prototype.toString.call(true)); // [object Boolean]
console.log(Object.prototype.toString.call('str')); // [object String]
console.log(Object.prototype.toString.call([])); // [object Array]
console.log(Object.prototype.toString.call(function(){})); // [object Function]
console.log(Object.prototype.toString.call({})); // [object Object]
console.log(Object.prototype.toString.call(undefined)); // [object Undefined]
console.log(Object.prototype.toString.call(null)); // [object Null]

console.log(Object.prototype.toString([])); // [object Object]
console.log(Object.prototype.toString(function() {})); // [object Object]

为什么Object.prototype.toString()Object.prototype.toString.call()的检测结果不一样?因为Object.prototype.toString()Object的原型方法,而ArrayFunction等类型作为Object的实例,都重写了toString方法,利用call是为了让()里面需要判断类型的数据类型来调用Object.prototype.toString方法

手写类型检测方法

实现思路

  1. null直接返回null

  2. 基本数据类型直接用typeof

  3. 引用数据类型用Object.prototype.toString

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function testType(target) {
if (target === null) return 'null';

if (typeof target !== 'object') return typeof target;

return Object.prototype.toString.call(target).slice(8, -1).toLowerCase(); // [object XXX]
};


// test
const target1 = [1,2,3];
const target2 = true;

console.log(testType(target1)); // array
console.log(testType(target2)); // boolean