typeof 只能检测基本数据类型和函数, instanceof不能检测基本数据类型
如何一句话检测数据类型呢?
function _typeof(value) {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}
结果是一个全为小写的字符串
下面来一步一步分析这段代码 :
原型链解析
Object 是原型链中最上层的构造函数,但 Object.prototype 才是原型链的顶端。
在 JavaScript 中,所有对象最终都继承自 Object.prototype,但 Object 作为构造函数,也有自己的原型关系
- Object 是构造函数
console.log(typeof Object); // "function"
它本质上是一个函数,用于创建对象。
- Object.prototype 是原型链的顶端
console.log(Object.prototype.__proto__); // null 注意__proto__前后都是两个下划线
Object.prototype 没有再往上的 proto,因此它是原型链的最顶层。
- Object 作为一个函数,也有自己的原型
console.log(Object.__proto__ === Function.prototype); // true
Object 作为函数,继承自 Function.prototype。
这意味着 所有构造函数(包括 Object 自己)最终都继承自 Function.prototype。
toString
Object.prototype.toString():将对象转换为字符串,通常是将对象的类型表示为 [object Type]
- 第一个 “object” → 固定前缀,表示这个值是一个对象(所有对象都会有这个前缀)。
- 第二个 “Object” → 对象的具体类型,
如果是没有加Object.prototype 那toString的结果只是一个字符串
console.log(Object.prototype.toString.call(123)); // "[object Number]"
console.log(Object.prototype.toString.call("hello")); // "[object String]"
console.log(Object.prototype.toString.call(true)); // "[object Boolean]"
console.log(Object.prototype.toString.call([])); // "[object Array]"
console.log(Object.prototype.toString.call({})); // "[object Object]"
console.log(Object.prototype.toString.call(null)); // "[object Null]"
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]"
console.log(Object.prototype.toString.call(function(){})); // "[object Function]"
console.log(Object.prototype.toString.call(new Date())); // "[object Date]"
call方法
如果没有call方法
看下面这段代码:
let string1 = "hello";
console.log(Object.prototype.toString(string1));
// ❌ 报错:TypeError: this is not a function or its prototype chain
实际上等价于:
Object.prototype.toString.call(undefined); // ❌ TypeError
因为 toString() 需要一个明确的 this 绑定,但你直接调用 Object.prototype.toString(value),没有指定 this,默认会把 this 绑定到 Object.prototype,导致错误。
如果 string1 是一个对象:
let string1 = new String("hello");
console.log(Object.prototype.toString(string1)); // "[object Object]"
.call(value) 手动指定 this 指向 value,这样 toString() 方法会正确地检查 value 的 [[Class]],然后返回 “[object Type]”。
slice(8, -1)
现在,我们已经知道 Object.prototype.toString.call(value) 返回的字符串形态是 “[object Type]”。
slice(8, -1) 的作用是 去除 [object 和 ],只留下 Type。
拆解 slice(8, -1)
假设 value = [],那么:
let str = Object.prototype.toString.call([]);
console.log(str); // "[object Array]"
📌 “Array” 这个部分从哪里开始?
"[object " 共有 8 个字符(索引 0~7),所以 索引 8 是 A(Array)。
“]” 在末尾,我们用 -1 让它被去掉。
效果如下:
let type = str.slice(8, -1); // 取索引 8 开始,到倒数第 2 个字符结束
console.log(type); // "Array"