前言

理解Javascript的类型是学习Javascript的基础,但是作为新手很容易在判断Javascript上容易混淆,所以在此整理清自己的思路。

类型

JavaScript 中所有变量都是对象,除了两个例外 null 和 undefined。

作为新手很容易被上面这句话误导,首先解释下上面这句话。

1
2
3
false.toString(); // 'false'
[1, 2, 3].toString(); // '1,2,3'
(2).toString(); // '2'

通过上面的代码,可以看出布尔、数组、数字都具有toString()这一方法,其实除了nullundefined外的数据类型都继承自Object对象都具Object的方法和属性,这些看似非对象的类型使用起来却很像对象,所以也可以说它们都是对象。可是Javascript依然具有类型,我想大致可以分成下面几类:

  • Number
  • String
  • Boolean
  • Object
  • Null
  • Undefined

NumberStringBooleanNullUndefined都是是基本数据类型,只有Object属于复杂数据类型。NullUndefined都表示空,它们的区别在于:Null表示无值,一般是人为的将变量的值设置为nullUndefined表示未知值,一般在使用var声明变量但未对其加以初始化时,这个变量值为undefined

Object又分为以下几种类型:

  • Object
    • Function
    • Array
    • Date
    • RegExp

typeof操作符

typeof操作符(和instanceof一起)或许是 JavaScript 中最大的设计缺陷, 因为几乎不可能从它们那里得到想要的结果。

1
2
3
4
5
6
7
8
9
10
typeof []; // object
typeof {}; // object
typeof ''; // string
typeof new Date() // object
typeof 1; // number
typeof function () {}; // function
typeof /test/i; // object
typeof true; // boolean
typeof null; // object
typeof undefined; // undefined

为什么?function明明是Object类型,却显示functionnull明明是Null类型,却显示’object’。所以typeof操作符对类型的判断是不靠谱的,除非类型在给定的范围且typeof确实能够区分这些类型。

类型的区分

Javascript标准标准文档给出了区分类型的办法:

1
Object.prototype.toString.call();

我们来看看上面的方法效果如何:

1
2
3
4
5
6
7
8
9
10
Object.prototype.toString.call([]); // [object Array]
Object.prototype.toString.call({}); // [object Object]
Object.prototype.toString.call(''); // [object String]
Object.prototype.toString.call(new Date()); // [object Date]
Object.prototype.toString.call(1); // [object Number]
Object.prototype.toString.call(function () {}); // [object Function]
Object.prototype.toString.call(/test/i); // [object RegExp]
Object.prototype.toString.call(true); // [object Boolean]
Object.prototype.toString.call(null); // [object Null]
Object.prototype.toString.call(); // [object Undefined]

效果确实比typeof操作符号不一样,那我们在判断的时候就可以这么使用了:

1
2
3
4
5
6
7
8
9
10
var getType = function (elem) {
return Object.prototype.toString.call(elem);
},
person = {};
person.getName = function () {
return 'Jason';
};
if (getType(person) === '[object Object]') {
person.getName();
}

可是这样还不够完美,因为Object.prototype.toString.call()返回值是字符串所以可以用.slice(8, -1)方法去掉[object]。所以我们再改进一下:

1
2
3
4
5
6
7
8
9
10
var getType = function (elem) {
return Object.prototype.toString.call(elem).slice(8, -1);
},
person = {};
person.getName = function () {
return 'Jason';
};
if (getType(person) === 'Object') {
person.getName();
}

写个类库

利用上面判断类型的方法可以写个类库,此类库来自(Axis.js)[//github.com/toddmotto/axis]:

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
(function (root, factory) {
// 判断是否使用了模块
if (typeof define === 'function' && define.amd) {
// 使用AMD模块
define(factory);
} else if (typeof exports === 'object') {
// 使用CMD模块
module.exports = factory;
} else {
// 没有使用模块,放在全局下
root.axis = factory();
}
})(this, function () {
// 严格模式
'use strict';
var exports = {};
// 将字符串转为数组
var types = 'Array Object String Date RegExp Function Boolean Number Null Undefined'.split(' ');
// 判断类型
var type = function () {
return Object.prototype.toString.call(this).slice(8, -1);
};
// 遍历types,为exports对象添加isArray、isObject...等方法
for (var i = types.length; i--;) {
exports['is' + types[i]] = (function (self) {
return function (elem) {
// type.call(elem)将type方法里的this指针指向elem
return type.call(elem) === self;
};
})(types[i]);
}
return exports;
});

使用方法也很简单:

1
2
3
4
5
6
7
8
9
10
axis.isArray([]); // true
axis.isObject({}); // true
axis.isString(''); // true
axis.isDate(new Date()); // true
axis.isRegExp(/test/i); // true
axis.isFunction(function () {}); // true
axis.isBoolean(true); // true
axis.isNumber(1); // true
axis.isNull(null); // true
axis.isUndefined(); // true

参考链接:

文章目录
  1. 1. 前言
  2. 2. 类型
  3. 3. typeof操作符
  4. 4. 类型的区分
  5. 5. 写个类库