js判断数据类型

114 阅读4分钟

在ES5的时候,js的数据类型分为两种:原始类型(即基本数据类型)和对象类型(即引用数据类型)。
基本数据类型包括 String、Number、Boolean、Undefined、Null;
引用数据类型也就是对象类型Object,比如:Object、Array、Function、Data等;
ES6 中新增了一种基本数据类型 Symbol ,用来表示独一无二的值。

let fc1 = '字符串' // String
let fc2 = 12 // Number
let fc3 = true // Boolean
// fc4 咱不声明变量fc4,所以fc4的数据类型是 Undefined
let fc5 = null // Null
let fc6 = {a: 1} // Object
let fc7 = [1, 2, 3] // Array
let fc8 = () => {} // Function
let fc9 = new Date() // Date (Object)
let fc10 = Symbol() // Symbol

typeof

最常见的判断方法
typeof是一个操作符,右侧跟一个一元表达式,返回这个表达式的数据类型,以字符串的形式表示;

typeof fc1 // 'string' ------------------ '字符串'
typeof fc2 // 'number' ------------------ 12
typeof fc3 // 'boolean' ----------------- true
typeof fc4 // 'undefined' --------------- undefined(未声明)
typeof fc5 // 'object' ------------------ null
typeof fc6 // 'object' ------------------ {a: 1}
typeof fc7 // 'object' ------------------ [1, 2, 3]
typeof fc8 // 'function' ---------------- () => {}
typeof fc9 // 'object' ------------------ new Date()
typeof fc10 // 'symbol' ----------------- Symbol()

注意:
1、typeof可以测试出NumberStringBooleanSymbolUndefinedFunction,而对于NullArrayObject,typeof均检测出为‘object’,不能进一步判断它们的类型;
2、typeof new Date()、typeof new RegExp()、typeof new Error()都会返回 'object';
3、typeof NaN会返回 'Number',NaN也是Number的一种;

instanceof

判断已知对象类型的方法
利用instanceof来判断A是否为B的实例,表达为A instanceof B,返回一个布尔值。instanceof的原理是通过检测对象的原型链上是否含有类型的原型。

fc6 instanceof Object // true ------------------ {a: 1}
fc7 instanceof Array // true ------------------- [1, 2, 3]
fc9 instanceof Date // true -------------------- new Date()

注意:
instanceof 后面一定要是对象类型,并且大小写不能错,该方法适合一些条件选择或分支。

Object.prototype.toString

通用但很繁琐的方法
Object.prototype.toString 方法能有效弥补typeof不能很好区分数组对象函数
每个类在内部都有一个 [[Class]] 属性,这个属性中就指定了上述字符串中的构造函数名。
Object.prototype.toString 的原理是当调用的时候,就取值内部的 [[Class]] 属性值, 然后拼接成 '[object ' + [[Class]] + ']' 这样的字符串并返回,然后我们使用 call 方法来获取任何值的数据类型。

Object.prototype.toString.call(fc1) // '[object String]' ------------------ '字符串'
Object.prototype.toString.call(fc2) // '[object Number]' ------------------ 12
Object.prototype.toString.call(fc3) // '[object Boolean]' ----------------- true
Object.prototype.toString.call(undefined) // '[object Undefined]' --------- undefined(未声明)
Object.prototype.toString.call(fc5) // '[object Null]' -------------------- null
Object.prototype.toString.call(fc6) // '[object Object]' ------------------ {a: 1}
Object.prototype.toString.call(fc7) // '[object Array]' ------------------- [1, 2, 3]
Object.prototype.toString.call(fc8) // '[object Function]' ---------------- () => {}
Object.prototype.toString.call(fc9) // '[object Date]' -------------------- new Date()
Object.prototype.toString.call(fc10) // '[object Symbol]' ----------------- Symbol()

constructor

JS规定,每个构造函数都会有一个prototype属性,即为构造函数的原型对象,而原型对象中会有一个constructor属性指回到构造函数。当利用构造函数创建新对象时,原型上的constructor属性也会被遗传到新创建的对象上,从原型链的角度讲,构造函数也代表了对象的类型。

fc1.constructor  === String // true ------------------ '字符串'
fc2.constructor  === Number // true ------------------ 12
fc3.constructor  === Boolean // true ----------------- true
fc6.constructor  === Object // true ------------------ {a: 1}
fc7.constructor  === Array // true ------------------- [1, 2, 3]
fc8.constructor  === Function // true ---------------- () => {}
fc9.constructor  === Date // true -------------------- new Date()
fc10.constructor  === Symbol // true ----------------- Symbol()

注意:
1、undefined和null没有contructor属性;
2、constructor 在类继承时会出错;

其他数据类型判断函数

Array.isArray()

用于确定传递的值是否是一个Array。如果对象是Array,则返回true,否则为false。

Array.isArray([1, 2, 3]);  
// true
Array.isArray({foo: 123}); 
// false
Array.isArray("foobar");   
// false
Array.isArray(undefined);  
// false

isNaN() 和 Number.isNaN()

isNaN()函数用来确定一个值是否为 NaN。
与 JavaScript 中其他的值不同, NaN不能通过相等操作符(== 和 ===)来判断 ,因为 NaN == NaN 和 NaN === NaN 都会返回 false。 因此,isNaN 就很有必要了。

isNaN(NaN); // true
// 看似很完美,但是接着看以下例子
isNaN('A String'); // true
isNaN(undefined); // true
isNaN({}); // true

会发现,很明显不是 NaN 的 value 也被误判成 NaN 了。
这个BUG已经存在了20年,从JavaScript最开始就一直存在。很明显当初的设计者,在设计isNaN()的时候,局限了在 "Not a Number" 这一字面意思上了:只要不是number就会返回 true。
于是 ES6 为了弥补这一BUG(而不是修正,因为isNaN存在时间太长,有可能很多功能都是基于这个BUG之上的)引入了 Number.isNaN().

Number.isNaN(NaN); // true
Number.isNaN('A String'); // false
Number.isNaN(undefined); // false
Number.isNaN({}); // false

没有ES6的情况下,可以采用以下polyfill

if (!Number.isNaN) {
  Number.isNaN = function(n) {
    return (
      typeof n === "number" &&
      window.isNaN( n )
    );
  };
}