判断 js 类型
js 有哪八大类型?(红宝书第四版)
- 原始类型(Primitive Types)
- string
- number
- boolean
- null
- undefined
- bigInt
- symbol
- object 引用类型(Reference Types)
- 基本引用类型
- Date
- RegExp
- 原始值包装类型 string,number,boolean 的包装类型
- 集合引用类型
- Object
- Array
- Map weakMap
- Set weakSet
- 定型数组
- 基本引用类型
判断 js 对象有四种方法
-
typeof
- 可以判断:typeof 可以准确判断除了 null 之外的 6 种原始类型,以及引用类型的 function。
- 无法判断:对于 null 返回'object',这是历史遗留的问题 对于除了 function 其他引用类型返回 'object'
- 为什么 typeof (() => {}) 会返回 function? 这里主要还是要看 ES6 中 typeof 是如何区分函数和对象类型的: 一个对象如果没有实现 [[Call]] 内部方法, 那么它就返回 object 一个对象如果实现了 [[Call]] 内部方法, 那么它就返回 function
-
Object.prototype.toString.call
- 原理: 返回一个格式为'[object xxx]'的字符串,其中 xxx 为首字母大写。对于原始类型的包装类型(new Number(1))和原始类型(1)结果相同
- 可以判断:原始类型和引用类型
- 注意点:这是一个比较全能的方法,但注意修改 Symbol.toStringTag 可以改变它的返回结果,并且例如 Object.prototype.toString.call(1)会进行包装(但区别于传统的隐式类型转换比如 1+'2' 把 1 转成字符串)
class MyObject { // 可以在构造函数中添加静态方法或属性来定义 @@toStringTag static get [Symbol.toStringTag]() { return "MyCustomObject"; } } const obj = new MyObject(); console.log(Object.prototype.toString.call(obj)); // 输出: [object MyCustomObject]
-
instanceOf & isPrototype
- 原理:确定原型链的位置
- 可以判断:引用值
- 不能判断:原始类型(例如数字 1 在原型链上没有位置)
- 代码示例
function Human(name, age) { this.name = name; this.age = age; } console.log(new Human() instanceof Human); //true console.log(new Human() instanceof Object); //true Object.prototype.isPrototypeOf(new Human()); //true -
constructor
- 原理:沿着实例对象.__proto__访问到构造函数的 constructor,判断该对象的 constructor 是否等于构造函数
- 可以判断:引用数据类型,并且可以直接确定上一级的父类
- 不能判断:原始数据类型、null、undefined,因为这几个数据没有 constructor
- 代码示例
Promise.resolve(1).constructor === Promise; //true,可以判断是Promise的new实例 Promise.resolve(1) instanceof Object; //true Promise.resolve(1) instanceof Promise; //true,无法确定是new Object还是new Promise的
实际上 cosntructor 和 instanceof | isPrototype 都是根据原型链来确定类型,但是 constructor 是确定相邻父级的类型
需要研究的有
- 特殊方法
- 对象能判断什么,不能判断什么
- 对象能否判断父类
- 对象能否判断包装类
- 是否会进行隐式转换
一个精确判断类型的方法需要先怎么写?
先判断直接父类型 再判断它是否为引用类型的某个子类型(引用类型) 再判断是否为基础类型(基础类型)
对于引用类型 先用 constructor 判断,再用 object.prototype.toString.call,instanceof,isprototype 来判断 剩下原始数据数据类型直接用 typeof 来判断
/**
* 判断给定值的类型。
*
* 支持基本类型(string, number, boolean, null, undefined, symbol, bigint, function)
* 和通过构造函数或构造函数数组自定义的类型。
* 如果给定的值不是基本类型且没有提供有效的自定义类型,则使用
* Object.prototype.toString.call 获取其类型。
*
* @param {any} val - 要判断类型的值。
* @param {(Function|Function[])} [customType] - 可选的自定义类型,可以是单个构造函数或包含构造函数的数组。
* @returns {string} - 返回值的类型名称。
*/
function judgeType(val, customType) {
if (
["string", "number", "boolean", "null", "undefined", "symbol", "bigint", "function"].includes(
typeof val,
)
) {
return typeof val;
}
if (val === null) {
return "null";
}
//已经判断完所有基础类型,开始判断引用类型
if (customType) {
if (
customType === val.constructor ||
(Array.isArray(customType) && customType.includes(val.constructor))
) {
return val.constructor.name;
}
}
//已经用类型判断了相邻层级的类型,再用instanceof判断原型链的可能不相邻的关系
if (customType) {
if(Array.isArray(customType)){
cosnt F = customType.find(F => instanceof F);
return F.name;
}//todo 判断更具体的类型
if(val instanceof customType){
reutrn customType.name
}
}
return Object.prototype.toString.call(val).slice(8, -1);
}