js一共有7种数据类型:6种基本数据类型和1种引用数据类型:
6种基本数据类型包括:String boolean Number Symbol(ES6新增) Undefined Null
1种引用数据类型:Object(在JS中除了基本数据类型以外的都是对象,数据是对象,函数是对象,正则表达式是对象)
js的常见内置对象:Date,Array,Math,Number,Boolean,String,Array,RegExp,Function…

js原始数据类型和function可以使用typeof区分

typeof function(){}
// "function"

typeof 2
//"number"
 
typeof ""
//"string"
 
typeof true
//"boolean"
 
typeof undefined
//"undefined"
 
typeof Symbol(2)
// "symbol"

但是,很遗憾的一点是,typeof 在判断一个 object的数据的时候只能告诉我们这个数据是 object, 而不能细致的具体到是哪一种 object。所以要想区分对象、数组、null,单纯使用typeof是不行的。

因为:

typeof null
// "object"
 
typeof [8]
// "object"
 
typeof {}
// "object"

综上,typeof 无法区分null 、数组和对象。

instanceof 运算符
在使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 “object”。ECMAScript 引入了另一个 Java 运算符 instanceof 来解决这个问题。

instanceof 运算符与 typeof 运算符相似,用于识别正在处理的对象的类型。与 typeof 方法不同的是,instanceof 方法要求开发者明确地确认对象为某特定类型。例如:

var oStringObject = new String("hello world");
alert(oStringObject instanceof String);	//输出 "true"

这段代码问的是“变量 oStringObject 是否为 String 对象的实例?”oStringObject 的确是 String 对象的实例,因此结果是 “true”。尽管不像 typeof 方法那样灵活,但是在 typeof 方法返回 “object” 的情况下,instanceof 方法还是很有用的。

当然,instanceof 也可以判断一个实例是否是其父类型或者祖先类型的实例。

let person = function () {
}
let programmer = function () {
}
programmer.prototype = new person()
let nicole = new programmer()
nicole instanceof person // true
nicole instanceof programmer // true

通常我们会区分判断Array和Object
有时会用instanceof 来判断是不是一个对象的实例子

[] instanceof Array
 // true 这种方法可以判断数组,但不能区分对象
[] instanceof Object
// true  说明在判断数组上,数据会被instanceof判断为Object
 
null instanceof Object
// false 说明instanceof也不能区分null

下面介绍一种方法,对每一种数据类型都实用。

Object.prototype.toString.call(function(){})
// "[object Function]"
 
Object.prototype.toString.call(null)
//"[object Null]"
 
Object.prototype.toString.call([2])
"[object Array]"
 
Object.prototype.toString.call(undefined)
//"[object Undefined]"
 
Object.prototype.toString.call('stjd')
//"[object String]"
 
Object.prototype.toString.call(1)
//"[object Number]"
 
Object.prototype.toString.call(true)
//"[object Boolean]"
 
Object.prototype.toString.call(Symbol(3))
// "[object Symbol]"
 
Object.prototype.toString.call({q:8})
//"[object Object]"

var reg = /[hbc]at/gi;
Object.prototype.toString.call(reg); // "[object RegExp]"

Object.prototype.toString.call(function(){}); //"[object Function]"//这个方法就建立在js任何类型皆可视为对象

Object.prototype.toString.call()的例外:判断自定义类

function Person(name, age) {
    this.name = name;
    this.age = age;
}
var person = new Person("Rose", 18);
Object.prototype.toString.call(arr); // "[object Object]"

很明显Object.prototype.toString.call()这种方法不能准确判断person是Person类的实例,而只能用instanceof 操作符来进行判断,如下所示:

console.log(person instanceof Person); // true

再来思考, toString.call([2]) 意思就是改变方法中的this指向,指向传递进去的参数,也就是[2]。那我这样写不是更直观吗?[2].toString()。结果:

[2].toString()
//"2"
var obj = {a: 67}
console.log(obj.toString())
// [object Array]

对比上面两个返回的值是不一样的。这是因为[2].toString()调用的是数组的toSting()方法,而不是对象的toSting()方法。Array改写了Object的toString方法。

toSting.call()实际上就是 Object.prototype.toSting.call()

console.log(Object.prototype.toString.call([33]))  // [object Array]

而[2].toSting()实际上是

console.log(Array.prototype.toString.call([2])) //2

使用的过程中,可以这样封装函数

function isType(type) {
      return function(obj) {
        return {}.toString.call(obj) == "[object " + type + "]"
      }
    }
    
    var isObject = isType("Object")
    var isString = isType("String")
    var isArray = Array.isArray || isType("Array")
    var isFunction = isType("Function")
    var isUndefined = isType("Undefined")

补充:

  1. 引用类型通常叫做类(class),也就是说,遇到引用值,所处理的就是对象。
  2. JS数据类型的判断主要有三种方法:typeof、instanceof、Object.prototype.toString.call()
  3. typeof可以区分原始数据类型和function数据类型
  4. Object.prototype.toString.call()区分数据类型适用范围最大,但是无法区分自定义对象类型
  5. 区分自定义对象类型使用instanceof 操作符