『前端面试100问』之JS中如何判断数据类型

234 阅读3分钟

JavaScript中的数据类型有8种,分别是null, undefined, boolean, number, string, symbol, bigint, object, 除了对象(object)之外,其它统称为『基本类型』,其中,『symbol』是ES6新增的数据类型,『bigint』是ES10新增的数据类型,因此目前 JS 有 7 种基础类型,1 种对象类型。

那么,怎么判断某个值是这8种数据类型中的哪一种呢?JS 提供了 4 种方式:typeof、instanceof、constructor、Object.prototype.toString.call(),这 4 种判断方式的原理依据以及适用场景分别是什么呢,你会在这篇文章种找到答案。

一、typeof 运算符

typeof 运算符返回的是类型的字符串值,值得注意的是,null 类型和它的字符串之后不是对应的:

typeof undefined === 'undefined'; // true
typeof true === 'boolean'; // true
typeof 42 === 'number'; // true
typeof "42" === 'string'; // true
typeof { life: 42 }  === "object"; // true// ES6中新加入的类型
typeof Symbol() === "symbol"; // true// ES10中新加入的类型
typeof 123n === 'bigint'; // true

null 类型比较特殊:

typeof null === 'object'; // true

正确的返回结果应该是 'null',这是 JavaScript 种由来已久的 bug,从 JavaScript 诞生之初就存在,修复它会产生更多的 bug,所以保留至今。

另外,函数类型(function)、日期类型(date)、正则类型(regexp)都是对象类型。

typeof 运算符可以正确判断除了 null 类型之外的基础类型,但对对象类型无效。

二、instanceof 运算符

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

需要注意的是,如果改变构造函数的原型,那么就不一定能正确判断了,比如:

function Foo() {}
let obj = new Foo();
obj instanceof Foo // true, 因为 Object.getPrototypeOf(obj) === Foo.prototype
Foo.prototype = {} // 改变构造函数的原型
obj instanceof Foo // false, 因为 Foo.prototype 指向了一个空对象,这个空对象不在 obj 的原型链上

需要注意的是,如果表达式 obj instanceof Foo 返回 true,则并不意味着该表达式会永远返回 true,因为 Foo.prototype 属性的值有可能会改变,改变之后的值很有可能不存在于 obj 的原型链上,这时原表达式的值就会成为 false 或者借助于 __proto__ 伪属性,比如执行 obj.__proto__ = {} 之后,obj instanceof Foo 就会返回 false 了。

另外,instanceof 不能用于判断 nullundefined,不能正确判断字面量类型

    字面量:var XXX = 'yyy' // 'yyy'就是一个字面量
    实例对象:通过构造函数创建出来的对象为实例对象

    通过 new 关键字创建内置类型可以将字面量转为实例对象,比如:
    var ZZZ = new String(XXX)

三、constructor属性

constructor 属性返回创建此对象的数组函数的引用:

console.log((2).constructor === Number) // true
console.log((123n).constructor === BigInt) // true
console.log(("喵喵").constructor === String) // true
console.log((true).constructor === Boolean) // true
console.log(([]).constructor === Array) // true
console.log((function(){}).constructor === Function) // true
console.log(({})o.constructor === Object) // true

与 instanceof 类似,如果先创建一个对象,更改它的原型,之后创建该对象的实例,这种方式就不可靠了:

function A(){}
let a = new A() // 创建 A 的实例对象
a.constructor === A // true
A.prototype = new Array() // 改变 A 的原型对象
let b = new A() // 创建 A 的实例
b.constructor === A // false

constructor 属性与 instanceof 运算符类似,都不能保证正确判断数据类型。

四、Object.prototype.toString.call()

Object.prototype.toString.call() 是判断数据类型的终极大法,能够准确判断各种数据类型。

console.log(Object.prototype.toString.call(2))
console.log(Object.prototype.toString.call(123n))
console.log(Object.prototype.toString.call(true))
console.log(Object.prototype.toString.call("喵喵"))
console.log(Object.prototype.toString.call(function(){}))
console.log(Object.prototype.toString.call({}))
console.log(Object.prototype.toString.call(undefined))
console.log(Object.prototype.toString.call(null))
​
[object Number]
[object BigInt]
[object Boolean]
[object String]
[object Function]
[object Object]
[object Undefined]
[object Null]

Object.prototype.toString() // "[object Object]"

Object.prototype.toString()返回值类型,通过 call()this 绑定到要判断的变量,从而返回变量的类型。


❤️❤️❤️ 最后我想说,如果这篇文章对你有帮助,那就请你帮我三个小忙:

1.点个『赞👍🏻』,表示你对这篇文章的认可❤️❤️❤️

2.关注公众号「我是前端喵」,定期为你推送精选好文,上下班路上看一看,有用的知识不知不觉就增加了😊😊😊

3.向你的朋友推荐公众号「我是前端喵」,一起进步吧🌞🌞🌞