文章目录
  1. 1. 类型系统
  2. 2. 类型转化表
  3. 3. 类型判断
    1. 3.1. typeof
    2. 3.2. instanceof
    3. 3.3. Object.prototype.toString.call()
    4. 3.4. constructor
  4. 4. 各种检验方法对应值
  5. 5. 一些常用的校验函数

在JavaScript中,有5种简单数据类型和1种复杂数据类型,简单数据类型有:Undefined,Null,Boolean, Number和String;复杂数据类型是Object,Object中还细分了很多具体的类型,比如:Array,Function,Date,RegExp等等,还有我们自己定义的对象,自定义类型。今天我们就来探讨一下,使用什么方法判断一个出一个变量的类型。

类型系统

type.jpg

类型转化表

Value Boolean Number String
undefined false NaN “undefined”
null false 0 “null”
true true 1 “true”
false false 0 “false”
‘’ false 0 “”
‘123’ true 123 “123”
‘1a’ true NaN “1a”
0 false 0 “0”
1 true 1 “1”
Infinity true Infinity “Infinity”
NaN false NaN “NaN”
{} true NaN “[object Object]”

类型判断

typeof

  • 可以判别简单数据类型(null除外)
  • 不可判别具体的复杂数据类型(Function除外)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//1. 可以判别简单数据类型(`null`除外)
var obj = 1;
typeof obj; //"number"
obj = "abc"
typeof obj; //"string"
obj = false
typeof obj; //"boolean"
obj = undefined;
typeof obj; //"undefined"
obj = null;
typeof obj; //"object",WTF,其实这是js的一个bug,人艰不拆 T_T
//2. 不可判别具体的复杂数据类型(`Function`除外)
obj = function(){};
typeof obj; //"function"
obj = [];
typeof obj; //"object"
obj = {};
typeof obj; //"object"
obj = /w/g;
typeof obj //"object"
obj = new Error();
typeof obj //"object"

instanceof

instanceof左侧为查询变量,右侧为标识对象的类。

  • 能够判别复杂数据类型,但是不能判别具体的复杂数据类型和Object类型。
  • 不能判别简单数据类型,但是能判别通过基本包装行创建的变量。
  • 能够判别自定义类型。
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
31
32
33
console.log(
//1. 不能判别简单数据类型 (number、string、boolean、null、undefined),
99 instanceof Number,//false
"2" instanceof String,//false
true instanceof Boolean,//false
undefined instanceof Object,//false
null instanceof Object,//false

//2.能够判别复杂数据类型,
[] instanceof Array,//true
{} instanceof Object,//true
(function(){}) instanceof Function,//true
(new Date()) instanceof Date,//true
/\d/ instanceof RegExp,//true
(new Error()) instanceof Error,//true
//但是不能判别`具体的复杂数据类型`和Object类型
[] instanceof Object,//true
/\d/ instanceof Object//true
)
//但是使用基本包装类型创建的对象通过 instanceof 可以判别。
//如果指定obj = "abc"则obj保存的实际上就是abc的值,是一个基本类型。而如果指定obj = new String('abc')那么obj实际上保存的是一个指向字符串对象的指针。
var obj = new String('abc');
obj instanceof String//true
"abc" instanceof String//false

//3. 能够判别自定义类型
function Point(x, y) {
this.x = x;
this.y = y;
}
var c = new Point(2,3);

c instanceof Point;//true

Object.prototype.toString.call()

  • 能判别所有类型(除去自定义类型)
  • 不能判别自定义类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//1. 所有类型(除去自定义类型)
console.log(
Object.prototype.toString.call(1),// '[object Number]'
Object.prototype.toString.call("abc"),//'[object String]'
Object.prototype.toString.call(true),//'[object Boolean]'
Object.prototype.toString.call([]),//'[object Array]'
Object.prototype.toString.call({}),//'[object Object]'
Object.prototype.toString.call(function(){}),//'[object Function]'
Object.prototype.toString.call(undefined),//'[object Undefined]'
Object.prototype.toString.call(null),//'[object Null]'
Object.prototype.toString.call(new Date()),//'[object Date]'
Object.prototype.toString.call(/^[a-zA-Z]{5,20}$/),//'[object RegExp]'
Object.prototype.toString.call(new Error())//'[object Error]'
);

//2. 不能判别自定义类型
function Point(x, y) {
this.x = x;
this.y = y;
}

var c = new Point(2,3);//c instanceof Point;//true
Object.prototype.toString.call(c);//"[object Object]"

简单封装

1
2
3
4
5
6
function typeProto(obj) {
return Object.prototype.toString.call(obj).slice(8,-1);
}

typeProto("guo");//"String"
typeProto({});//"Object"

constructor

constructor本来是原型对象上的属性,指向构造函数。但是根据实例对象寻找属性的顺序,若实例对象上没有实例属性或方法时,就去原型链上寻找,因此,实例对象也是能使用constructor属性的。

  • 不可判别nullundefined
  • 可判别简单类型数据(nullundefined除外)
  • 可判别复杂类型数据包括自定义类型数据
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function Person(){}
    var Tom = new Person();
    // undefined和null没有constructor属性
    console.log(
    Tom.constructor === Person,
    (2).constructor === Number,//或者 2..constructor
    "abc".constructor === String,
    true.constructor === Boolean,
    [].constructor === Array,
    {}.constructor === Object,
    (function aa(){}).constructor === Function,
    (new Date()).constructor === Date,
    /\d/.constructor === RegExp,
    (new Error()).constructor === Error
    );

不过使用constructor也不是保险的,因为constructor属性是可以被修改的,会导致检测出的结果不正确,例如:

1
2
3
4
5
6
function Person(){}
function Student(){}
Student.prototype = new Person();
var John = new Student();
console.log(John.constructor==Student); // false
console.log(John.constructor==Person); // true

在上面的例子中,Student原型中的constructor被修改为指向到Person,导致检测不出实例对象John真实的构造函数。
注意:
同时,使用instaceofconstrucor,被判断的array必须是在当前页面声明的!比如,一个页面(父页面)有一个框架,框架中引用了一个页面(子页面),在子页面中声明了一个array,并将其赋值给父页面的一个变量,这时在父页面判断该变量,Array(父页面的Array构造函数) === object(子页面穿过来的字页面的Array对象).constructor;肯定会返回false;原因:

  1. array属于引用型数据,在传递过程中,仅仅是引用地址的传递。
  2. 每个页面的Array原生对象所引用的地址是不一样的,在子页面声明的array,所对应的构造函数,是子页面的Array对象;父页面来进行判断,使用的Array并不等于子页面的Array;切记,不然很难跟踪问题!

各种检验方法对应值

类型判断 typeof instanceof constructor toString.call $.type(jQuery库的方法)
99 number false true [object Number] number
“abc” string false true [object String] string
true boolean false true [object Boolean] boolean
[1,2] object true true [object Array] array
{} object true true [object Object] object
(function aa(){}) function true true [object Function] function
undefined undefined false - [object Undefined] undefined
null object false - [object Null] null
new Date() object true true [object Date] date
/\d/ object true true [object RegExp] regexp
new Error() object true true [object Error] error
优点 使用简单,能直接输出结果 能检测出复杂的类型 基本能检测出所有的类型 检测出所有的类型 -
缺点 检测出的类型太少 基本类型检测不出,且不能跨iframe 不能跨iframe,且constructor易被修改 IE6下undefined,null均为Object -
$.type 原理:先判断 undefined 和 null
obj == null ? String( obj ) : Object.prototype.toString.call(obj)

一些常用的校验函数

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
31
32
33
34
35
36
37
38
39
40
//低版本ie中undefined变量可以被修改,所以使用void 0 获取真实的undefined值,
var isUndefined = function(obj) {
//or: return typeof obj === 'undefined';
return obj === void 0;
};
//typeof null 的结果是"object"。
var isNull = function(obj) {
return obj === null;
};
// boolean值,number值和string值需要考虑两种情况,值为字面量时使用typeof和Object.prototype.toString能检测;
// 值为构造函数构建的时候需要使用Object.prototype.toString或者instanceof检测
var isBoolean = function(obj) {
return Object.prototype.toString.call(obj) == '[object Boolean]';
};
var isNumber = function(obj) {
return Object.prototype.toString.call(obj) == '[object Number]';
};
var isString = function(obj) {
return Object.prototype.toString.call(obj) == '[object String]';
};
var isNaN = function(obj) {
return obj !== obj;
};

//typeof 操作符在引用类型的变量里能对function有效。
var isFunction = function(obj) {
//or: return Object.prototype.toString.call(obj) == '[object Function]';
return typeof obj === 'function';

};
var isDate = function(obj) {
return Object.prototype.toString.call(obj) == '[object Date]';
}
var isArray = function(obj) {
return Object.prototype.toString.call(obj) == '[object Array]';
}
var isObject = function(obj) {
//or: return obj === Object(obj);
return Object.prototype.toString.call(obj) == '[object Object]';
}
文章目录
  1. 1. 类型系统
  2. 2. 类型转化表
  3. 3. 类型判断
    1. 3.1. typeof
    2. 3.2. instanceof
    3. 3.3. Object.prototype.toString.call()
    4. 3.4. constructor
  4. 4. 各种检验方法对应值
  5. 5. 一些常用的校验函数