1、typeof
typeof
操做符惟一的目的就是检查数据类型php
类型 | typeof 结果 | |
---|---|---|
基本类型 | undefined | "undefined" |
Boolean | "boolean" | |
Number | "number" | |
String | "string" | |
BigInt (ECMAScript 2020 新增) | "bigint" | |
Symbol | "symbol" | |
null | "object" | |
引用类型 | Object(Object、Array、Map、Set等) | "object" |
Function | "function" |
因此,但咱们使用 typeof
来判断引用类型变量时,不管是什么类型的变量,它都会返回 Object
。html
为此,引入了instanceof
。前端
2、instanceof
instanceof
与 typeof
相比,instanceof
方法要求开发者明确的确认对象为某特定类型。即 instanceof
用于判断引用类型属于哪一个构造函数的方法。git
var arr = [] arr instanceof Array // true typeof arr // "object" // typeof 是没法判断类型是否为数组的
instanceof
操做符检测过程当中也会将继承关系考虑在内,因此instanceof
能够在继承关系中用来判断一个实例是否属于它的父类型。github
// 判断 f 是不是 Foo 类的实例 , 而且是不是其父类型的实例 function Aoo(){} function Foo(){} //JavaScript 原型继承 Foo.prototype = new Aoo(); var foo = new Foo(); console.log(foo instanceof Foo) // true console.log(foo instanceof Aoo) // true
f instanceof Foo
的判断逻辑是:面试
- f 的
__proto__
一层一层往上,是否对应到Foo.prototype
- 再往上,看是否对应着
Aoo.prototype
- 再试着判断
f instanceof Object
即 instanceof
能够用于判断多层继承关系。算法
3、instanceof 的内部实现原理
instanceof 的内部实现机制是:经过判断对象的原型链上是否能找到对象的 prototype
,来肯定 instanceof
返回值数组
1. 内部实现原理
// instanceof 的内部实现 function instance_of(L, R) {//L 表左表达式,R 表示右表达式,即L为变量,R为类型 // 取 R 的显示原型 var prototype = R.prototype // 取 L 的隐式原型 L = L.__proto__ // 判断对象(L)的类型是否严格等于类型(R)的显式原型 while (true) { if (L === null) { return false } // 这里重点:当 prototype 严格等于 L 时,返回 true if (prototype === L) { return true } L = L.__proto__ } }
instanceof
运算符用来检测 constructor.prototype
是否存在于参数 object
的原型链上。浏览器
看下面一个例子,instanceof
为何会返回 true
?很显然,an
并非经过 Bottle()
建立的。ecmascript
function An() {} function Bottle() {} An.prototype = Bottle.prototype = {}; let an = new An(); console.log(an instanceof Bottle); // true
这是由于 instanceof
关心的并非构造函数,而是原型链。
an.__proto__ === An.prototype; // true An.prototype === Bottle.prototype; // true // 即 an.__proto__ === Bottle.prototype; // true
即有 an.__proto__ === Bottle.prototype
成立,因此 an instanceof Bottle
返回了 true
。
因此,按照 instanceof
的逻辑,真正决定类型的是 prototype
,而不是构造函数。
2. Object.prototype.toString(扩展)
还有一个不错的判断类型的方法,就是 Object.prototype.toString
,咱们能够利用这个方法来对一个变量的类型来进行比较准确的判断
默认状况下(不覆盖 toString
方法前提下),任何一个对象调用 Object
原生的 toString
方法都会返回 "[object type]"
,其中 type
是对象的类型;
let obj = {}; console.log(obj); // {} console.log(obj.toString()); // "[object Object]"
[[Class]]
每一个实例都有一个 [[Class]]
属性,这个属性中就指定了上述字符串中的 type
(构造函数名)。 [[Class]]
不能直接地被访问,但一般能够间接地经过在这个值上借用默认的 Object.prototype.toString.call(..)
方法调用来展现。
Object.prototype.toString.call("abc"); // "[object String]" Object.prototype.toString.call(100); // "[object Number]" Object.prototype.toString.call(true); // "[object Boolean]" Object.prototype.toString.call(null); // "[object Null]" Object.prototype.toString.call(undefined); // "[object Undefined]" Object.prototype.toString.call([1,2,3]); // "[object Array]" Object.prototype.toString.call(/\w/); // "[object RegExp]"
能够经过 Object.prototype.toString.call(..)
来获取每一个对象的类型。
function isFunction(value) { return Object.prototype.toString.call(value) === "[object Function]" } function isDate(value) { return Object.prototype.toString.call(value) === "[object Date]" } function isRegExp(value) { return Object.prototype.toString.call(value) === "[object RegExp]" } isDate(new Date()); // true isRegExp(/\w/); // true isFunction(function(){}); //true
或者可写为:
function generator(type){ return function(value){ return Object.prototype.toString.call(value) === "[object "+ type +"]" } } let isFunction = generator('Function') let isArray = generator('Array'); let isDate = generator('Date'); let isRegExp = generator('RegExp'); isArray([])); // true isDate(new Date()); // true isRegExp(/\w/); // true isFunction(function(){}); //true
Symbol.toStringTag
Object.prototype.toString
方法可使用 Symbol.toStringTag
这个特殊的对象属性进行自定义输出。
举例说明:
let bottle = { [Symbol.toStringTag]: "Bottle" }; console.log(Object.prototype.toString.call(bottle)); // [object Bottle]
大部分和环境相关的对象也有这个属性。如下输出可能因浏览器不一样而异:
// 环境相关对象和类的 toStringTag: console.log(window[Symbol.toStringTag]); // Window console.log(XMLHttpRequest.prototype[Symbol.toStringTag]); // XMLHttpRequest console.log(Object.prototype.toString.call(window)); // [object Window] console.log(Object.prototype.toString.call(new XMLHttpRequest())); // [object XMLHttpRequest]
输出结果和 Symbol.toStringTag
(前提是这个属性存在)同样,只不过被包裹进了 [object ...]
里。
因此,若是但愿以字符串的形式获取内置对象类型信息,而不只仅只是检测类型的话,能够用这个方法来替代 instanceof
。
3. 总结
适用于 | 返回 | |
---|---|---|
typeof | 基本数据类型 | string |
instanceof | 任意对象 | true/false |
Object.prototype.toString |
基本数据类型、内置对象以及包含 Symbol.toStringTag 属性的对象 |
string |
Object.prototype.toString
基本上就是一加强版 typeof
。
instanceof
在涉及多层类结构的场合中比较实用,这种状况下须要将类的继承关系考虑在内。
4、null为何被typeof错误的判断为了'object'
// JavaScript 诞生以来便如此 typeof null === 'object';
在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。因为 null
表明的是空指针(大多数平台下值为 0x00),所以,null 的类型标签是 0,typeof null
也所以返回 "object"
。(参考来源)
曾有一个 ECMAScript 的修复提案(经过选择性加入的方式),但被拒绝了。该提案会致使 typeof null === 'null'
。
若是用 instanceof
来判断的话:
null instanceof null // Uncaught TypeError: Right-hand side of 'instanceof' is not an object