要想判断数据类型,首先要知道数据类型的分类。数据类型分为基本数据类型和引用数据类型。正则表达式
基本数据类型有 五 种,ES6中新加了第 六 种基本数据类型——Symbol 类型。编程
引用类型数据也会统称为对象,即广义的对象,一般除了基本数据类型的其它数据都属于引用类型数据。数组
{key1:value1, key2:value2,...}
[value1,value2,...]
typeof
返回字符串,number
、string
、boolean
、symbol
、undefined
、function
,全部其它的引用类型数据都返回 object
,null
也返回 object
。浏览器
typeof 666 // "number" typeof 'dora' // "string" typeof true // "boolean" typeof Symbol() // "symbol" typeof undefined // "undefined" typeof null // "object" typeof function(){} // "function" typeof [] // "object" typeof /dora/ // "object"
可利用判断 undefined
来检查一个没有声明的变量,而不报错。实际编程中,这个特色一般用在判断语句中。函数
// 错误的写法 if (v) { // ... } // ReferenceError: v is not defined // 正确的写法 if (typeof v === "undefined") { // 这种写法在 v 没有声明的时候不会报错。 }
注意this
ES6中引入了 let
以后,这个方法也不是万能的了。当变量在代码块内用 let
声明的时候,会造成“暂时性死区”(temporal dead zone,简称 TDZ),此时这个方法就没用了,typeof 仍是会报错。prototype
typeof x; // ReferenceError let x;
不能准确的判断引用类型数据的具体类型,除了函数外,其他的都是返回object
。code
typeof {} // "object" typeof [] // "object"
此时,在须要判断数组或者对象时,就不适用了。regexp
Object.prototype.toString()
方法返回对象的类型字符串,所以能够用来判断一个值的类型。对象
var obj = {}; obj.toString() // "[object Object]"
上面代码调用空对象的toString方法,结果返回一个字符串 object Object
,其中第二个Object表示该值的 构造函数。
因为实例对象可能会自定义toString方法,覆盖掉 Object.prototype.toString
方法,因此为了获得类型字符串,最好直接使用Object.prototype.toString
方法。经过函数的call
方法,能够在任意值上调用这个方法,帮助咱们判断这个值的类型。
Object.prototype.toString.call(value)
上面代码表示对value这个值调用Object.prototype.toString
方法。
不一样数据类型的Object.prototype.toString
方法返回值以下:
[object Number]
。[object String]
。[object Boolean]
。[object Undefined]
。[object Null]
。[object Symbol]
。[object Array]
。[object Arguments]
。[object Function]
。[object Error]
。[object Date]
。[object RegExp]
。[object Object]
。Object.prototype.toString.call(2) // "[object Number]" Object.prototype.toString.call('') // "[object String]" Object.prototype.toString.call(true) // "[object Boolean]" Object.prototype.toString.call(undefined) // "[object Undefined]" Object.prototype.toString.call(null) // "[object Null]" Object.prototype.toString.call(Symbol()) // "[object Symbol]" Object.prototype.toString.call(Math) // "[object Math]" Object.prototype.toString.call({}) // "[object Object]" Object.prototype.toString.call([]) // "[object Array]"
利用这个特性,能够封装一个比typeof
运算符更准确的类型判断函数。
var type = function (o){ var s = Object.prototype.toString.call(o); return s.match(/\[object (.*?)\]/)[1].toLowerCase(); }; type({}); // "object" type([]); // "array" type(5); // "number" type(null); // "null" type(); // "undefined" type(/dora/); // "regexp" type(new Date()); // "date"
在上面这个type函数的基础上,还能够加上专门判断某种类型数据的方法。
var dataArr = ['Null', 'Undefined', 'Object', 'Array', 'String', 'Number', 'Boolean', 'Function', 'RegExp']; dataArr.forEach(function (t) { type['is' + t] = function (o) { return type(o) === t.toLowerCase(); }; }); type.isObject({}); // true type.isNumber(NaN); // true type.isRegExp(/abc/); // true
instanceof
运算符返回一个布尔值,表示对象是否为某个构造函数的实例。
function People(){} var person = new People(); person instanceof People // true
遍访对象的原型链上的每一个原型对象,若是遍访到这个原型对象,是某个构造函数的prototype
,那么就认为对象是这个构造函数的实例,返回true。所以同一个实例对象,可能会对多个构造函数都返回true,由于继承的子类实例也是父类的实例。
var d = new Date(); d instanceof Date // true d instanceof Object // true
特殊状况
有一种特殊状况,就是左边对象的原型链上,只有null对象。这时,instanceof
判断会失真。
var obj = Object.create(null); typeof obj // "object" obj instanceof Object // false
上面代码中,Object.create(null)
返回一个新对象obj
,它的原型是null
。右边的构造函数Object
的prototype
属性,不在左边的原型链上,所以instanceof
就认为obj
不是Object
的实例。
只要一个对象的原型不是null
,instanceof
运算符的判断就不会失真。
instanceof
运算符只能用于对象,不适用原始类型的值,且对于undefined
和null
,instanceof
运算符老是返回false
。
'hello' instanceof String // false undefined instanceof Object // false null instanceof Object // false
可用于对象,不管是 JavaScript 内置对象或是自定义构造函数生成的对象,均可进行判断。
[] instanceof Array // true ({}) instanceof Object // true (function(){}) instanceof Function // true /a/ instanceof RegExp // true new Date() instanceof Date // true person instanceof People // true
prototype
对象有一个constructor
属性,默认指向prototype
对象所在的构造函数。因为constructor
属性定义在prototype
对象上面,意味着能够被全部实例对象继承。所以,正常状况下,全部对象实例都有一个constructor
属性,属性值指向构造此对象实例的构造函数。
[].constructor === Array // true [].constructor === Object // false window.constructor === Window //true
若是不能肯定对象实例的constructor
属性是什么函数,可经过函数的name
属性,从实例获得构造函数的名称。
function Foo() {} var f = new Foo(); f.constructor.name // "Foo"
基本数据类型
null
和undefined
是无效的对象,所以是不会有constructor
存在的,这两种类型的数据须要经过typeof
来判断。
number
、string
、boolean
三种数据类型有对应的Number
、String
、Boolean
三个原生对象(包装对象)。所以,也可用 constructor
进行判断。symbol
类型也可判断。
(333).constructor.name // "Number" ''.constructor.name // "String" false.constructor.name // "Boolean" Symbol().constructor.name // "Symbol"
引用数据类型
JavaScript 内置对象或是自定义构造函数生成的对象,均可进行判断。
new Date().constructor === Date //true [].constructor === Array //true function F(){}; var f = new F(); f.constructor === F // true f.constructor === Object // false
constructor
属性表示原型对象与构造函数之间的关联关系,有时开发者会因业务关系重写prototype
,原有的constructor
会丢失,若没有同时修改constructor
属性,引用的时候就会出错,constructor
会默认为Object
。
function Person(name) { this.name = name; } Person.prototype.constructor === Person // true Person.prototype = { method: function () {} }; Person.prototype.constructor === Person // false Person.prototype.constructor === Object // true
所以,修改原型对象时,通常要同时修改constructor
属性的指向,或者只在原型对象上添加方法,不要重写prototype
。
typeoftypeof
可用来判断基本数据类型和函数,不能够对引用数据类型进行具体的判断。
Object.prototype.toString.call(value)Object.prototype.toString.call(value)
可用于判断多种数据类型:基本数据类型和 JavaScript 内置对象,然而对于一些自定义构造函数生成的对象就不能进行判断了。
instanceofinstanceof
运算符不适用判断原始类型的值,只能用于判断对象,不管是 JavaScript 内置对象或是自定义构造函数生成的对象,均可进行判断。然而因为继承的存在,instanceof
判断也不彻底准确,只能用来判断两个对象是否属于原型链的关系,而不必定能获取对象的具体类型。
constructorconstructor
属性可准确的判断对象实例是由哪一个构造函数生成的,但自定义构造函数生成的对象,每每会由于重写prototype
形成constructor
属性指向不许确,所以使用的时候也要注意一下。
Object(x)
的参数为对象时,老是返回该对象,不作转换;当参数为原始类型时,会转换为对应的包装对象的实例,参数为空或者undefined
或者null
时,返回一个空对象。
function isObject(value) { return value === Object(value); } isObject([]); // true isObject(true); // false
全部数据类型中,只有NaN
不等于它自己
function isNaN(value) { return value !== value; } isNaN(NaN); // true
除了上文提到的三种方法(toString()
、instanceof
、constructor
)可判断外,还有一个Array
构造函数自带的方法isArray()
可判断。
Array.isArray(x)
若是x
是数组,则为true
; 不然为false
。
Array.isArray([]); // true Array.isArray(new Array()); // true Array.isArray(Array.prototype); // true 不为人知的事实:其实 Array.prototype 也是一个数组。
使用以前需检测一下兼容性,对于不兼容的浏览器可以使用下面的代码建立该方法。
if (!Array.isArray) { Array.isArray = function(arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }; }