JavaScript专题之类型判断(上)
jQuery type源码
参考

1
2
3
Object.prototype.toString.call(arguments); // [object Arguments]
Object.prototype.toString.call(location) // "[object Location]"
Object.prototype.toString.call(history) // "[object History]"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var class2type = {};

// 生成class2type映射
"Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item, index) {
class2type["[object " + item + "]"] = item.toLowerCase();
})

function type(obj) {
// 在 IE6 中,null 和 undefined 会被 Object.prototype.toString 识别成 [object Object]!
if (obj == null) {
return obj + "";
}
return typeof obj === "object" || typeof obj === "function" ?
class2type[Object.prototype.toString.call(obj)] || "object" :
typeof obj;
}

假设 Object.prototpye.toString()是未被修改过的原生版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Typeof {
isNull(o) { //是否为null
return Object.prototype.toString.call(o).slice(8, -1) === 'Null'
}

isUndefined(o) { //是否undefined
return Object.prototype.toString.call(o).slice(8, -1) === 'Undefined'
}

isSymbol(o) { //是否Symbol函数
return Object.prototype.toString.call(o).slice(8, -1) === 'Symbol'
}

isPromise(o) { //是否Promise对象
return Object.prototype.toString.call(o).slice(8, -1) === 'Promise'
}

isSet(o) { //是否Set对象
return Object.prototype.toString.call(o).slice(8, -1) === 'Set'
}

isFalse(o) {
if (!o || o === 'null' || o === 'undefined' || o === 'false' || o === 'NaN') return true
return false
}

isTrue(o) {
return !this.isFalse(o)
}
}

标准内置对象的分类

1
这些全局属性返回一个简单值,这些值没有自己的属性和方法。
值属性 描述
Infinity 一个数值,表示无穷大
NaN 不是一个数字(Not-A-Number)
undefined 原始值undefined。它是一个JavaScript的 原始数据类型
null字面量 特指对象的值未设置

全局函数可以直接调用,不需要在调用时指定所属对象,执行结束后会将结果直接返回给调用者。

函数属性 描述
eval()
isFinite()
isNaN()
parseFloat()
parseInt()
decodeURI()
decodeURIComponent()
encodeURI()
encodeURIComponent()

顾名思义,基本对象是定义或使用其他对象的基础。基本对象包括一般对象、函数对象和错误对象。

基本对象 描述
Object
Function
Boolean
Symbol
Error
EvalError
InternalError
RangeError
ReferenceError (引用错误)对象代表当一个不存在的变量被引用时发生的错误
SyntaxError
TypeError
URIError

用来表示数字、日期和执行数学计算的对象。
数字和日期对象节 | 描述
—|—
Number
Math
Date

用来表示和操作字符串的对象。

字符串 描述

String
RegExp

这些对象表示按照索引值来排序的数据集合,包括数组和类型数组,以及类数组结构的对象。
可索引的集合对象 | 描述
—|—
Array |
… |

这些集合对象在存储数据时会使用到键,支持按照插入顺序来迭代元素。
使用键的集合对象 |
—|—
Map |
Set |
WeakMap |
WeakSet |

这些对象用来表示和操作结构化的缓冲区数据,或使用 JSON (JavaScript Object Notation)编码的数据。
结构化数据 |
—|—
ArrayBuffer
DataView
JSON

控制抽象对象
Promise
Generator
GeneratorFunction
反射
Promise
Reflect
Proxy

其他
arguments

类型检测

typeof

一般用于检测原始数据类型,引用数据类型无法具体的检测出来

1
2
3
4
5
6
7
8
console.log(typeof ""); //string
console.log(typeof 1); //number
console.log(typeof true); //boolean
console.log(typeof null); //object
console.log(typeof undefined); //undefined
console.log(typeof []); //object
console.log(typeof function() {}); //function
console.log(typeof {}); //object

其实null是js设计的一个败笔,早期准备更改null的类型为null,由于当时已经有大量网站使用了null,如果更改,将导致很多网站的逻辑出现漏洞问题,就没有更改过来,于是一直遗留到现在。

instanceof

检测引用数据类型

1
2
3
4
5
6
console.log("1" instanceof String);  //false
console.log(1 instanceof Number); //false
console.log(true instanceof Boolean); //false
console.log([] instanceof Array); //true
console.log(function() {} instanceof Function); //true
console.log({} instanceof Object); //true

可以看到前三个都是以对象字面量创建的基本数据类型,但是却不是所属类的实例,这个就有点怪了。后面三个是引用数据类型,可以得到正确的结果。如果我们通过new关键字去创建基本数据类型,你会发现,这时就会输出true,如下:

1
2
3
4
5
6
console.log(new String("1") instanceof String); //true
console.log(new Number(1) instanceof Number); //true
console.log(new Boolean(true) instanceof Boolean); //true
console.log([] instanceof Array); //true
console.log(function() {} instanceof Function); //true
console.log({} instanceof Object); //true

constructor

似乎完全可以应对基本数据类型和引用数据类型,都能检测出数据类型

1
2
3
4
5
6
console.log(("1").constructor === String); //true
console.log((1).constructor === Number); //true
console.log((true).constructor === Boolean); //true
console.log(([]).constructor === Array); //true
console.log((function() {}).constructor === Function); //true
console.log(({}).constructor === Object); //true

事实上并不是如此,来看看为什么:

1
2
3
4
5
6
function Fn(){};
Fn.prototype=new Array();
var f=new Fn();

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

声明了一个构造函数,并且把他的原型指向了Array的原型,所以这种情况下,constructor也显得力不从心了。

toString

Object.prototype.toString终极数据检测方式

1
2
3
4
5
6
7
8
9
10
var a = Object.prototype.toString;

console.log(a.call("aaa")); //[object String]
console.log(a.call(1)); //[object Number]
console.log(a.call(true)); //[object Boolean]
console.log(a.call(null)); //[object Null]
console.log(a.call(undefined)); //[object Undefined]
console.log(a.call([])); //[object Array]
console.log(a.call(function() {})); //[object Function]
console.log(a.call({})); //[object Object]