本文详细解析 JavaScript 中 typeof 与 instanceof 的区别。typeof 用于判断基础数据类型,但 null 返回 object;instanceof 基于原型链判断引用类型。针对两者局限,介绍使用 Object.prototype.toString 实现通用的数据类型检测方法,涵盖数组、日期、正则等复杂类型的准确识别。
一、typeof
typeof 操作符返回一个字符串,表示未经计算的操作数的类型。具体使用方法如下:
typeof operand
typeof(operand)
其中 operand 表示对象或原始值的表达式,其类型将被返回。以下是一个具体示例:
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof null // 'object'
typeof [] // 'object'
typeof {} // 'object'
typeof console // 'object'
typeof console.log // 'function'
从上述示例可以看出,前 6 个结果对应基础数据类型。尽管 typeof null 返回 'object',但这仅是 JavaScript 语言中一个历史遗留的 Bug,并不意味着 null 属于引用数据类型,且 null 本身也不是对象。
因此,null 在 typeof 运算后的结果存在偏差,不适合作为判断 null 的依据。若需在 if 语句中判断变量是否为 null,应直接使用 === null 进行严格比较。
同时可以发现,对于引用类型数据,使用 typeof 判断时,除了 function 类型会被正确识别外,其余所有引用类型均返回 'object'。若需判断一个变量是否已声明存在,可以使用 typeof:(注意:不能直接使用 if(a),若 a 未声明,直接访问会报错)。
if(typeof a != 'undefined'){
//变量存在
}
二、instanceof
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。具体使用方式如下:
object instanceof constructor
其中 object 为实例对象,constructor 为构造函数。构造函数通过 new 关键字可以创建实例对象,instanceof 能够判断该对象是否由指定的构造函数生成。
// 定义构建函数
let Car = function() {}
let benz = new Car()
benz instanceof Car // true
let car = new String('xxx')
car instanceof String // true
let str = 'xxx'
str instanceof String // false
关于 instanceof 的实现原理,可参考以下代码逻辑:
function myInstanceof(left, right) {
// 这里先用typeof来判断基础数据类型,如果是,直接返回false
if(typeof left !== 'object' || left === null) return false;
// getProtypeOf是Object对象自带的API,能够拿到参数的原型对象
let proto = Object.getPrototypeOf(left);
while(true) {
if(proto === null) return false;
if(proto === right.prototype) return true;//找到相同原型对象,返回true
proto = Object.getPrototypeof(proto);
}
}
其核心逻辑是顺着原型链向上查找,直到找到与构造函数 prototype 相同的对象则返回 true,否则返回 false。
三、区别
typeof 与 instanceof 均为判断数据类型的方法,主要区别如下:
- typeof 会返回变量的基本类型字符串,而 instanceof 返回的是一个布尔值。
- instanceof 可以准确判断复杂引用数据类型,但无法正确判断基础数据类型。
- 而 typeof 也存在局限,虽然它可以判断基础数据类型(null 除外),但在引用数据类型中,除 function 类型外,其他类型均无法准确区分。
1. 对于对象、数组、null,返回的值均为 'object'。例如 typeof(window)、typeof(document)、typeof(null) 返回的值都是 'object'。 2. 对于函数类型,返回的值是 'function'。例如:typeof(eval)、typeof(Date) 返回的值都是 'function'。
由此可见,上述两种方法均存在局限性,无法完全满足所有场景下的类型检测需求。
如果需要通用的数据类型检测,可以采用 Object.prototype.toString,调用该方法后,统一返回格式为 '[object Xxx]' 的字符串。具体示例如下:
Object.prototype.toString({}) // "[object Object]"
Object.prototype.toString.call({}) // 同上结果,加上call也ok
Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call('1') // "[object String]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(function(){}) // "[object Function]"
Object.prototype.toString.call(null) //"[object Null]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(/123/g) //"[object RegExp]"
Object.prototype.toString.call(new Date()) //"[object Date]"
Object.prototype.toString.call([]) //"[object Array]"
Object.prototype.toString.call(document) //"[object HTMLDocument]"
Object.prototype.toString.call(window) //"[object Window]"
了解了 toString 的基本用法后,接下来实现一个全局通用的数据类型判断方法。
function getType(obj){
let type = typeof obj;
if (type !== "object") { // 先进行typeof判断,如果是基础数据类型,直接返回
return type;
}
// 对于typeof返回结果是object的,再进行如下的判断,正则返回结果
return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1');
}
具体使用方式如下:
getType([]) // "Array" typeof []是object,因此toString返回
getType('123') // "string" typeof 直接返回
getType(window) // "Window" toString返回
getType(null) // "Null"首字母大写,typeof null是object,需toString来判断
getType(undefined) // "undefined" typeof 直接返回
getType() // "undefined" typeof 直接返回
getType(function(){}) // "function" typeof能判断,因此首字母小写
getType(/123/g) //"RegExp" toString返回
到此这篇关于菜鸟也能搞懂js中typeof与instanceof区别的文章就介绍到这了,更多相关js中typeof与instanceof内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!