前言
作者最近在看神三元大佬的JS灵魂之问系列和程序员鱼皮的面试鸭的八股系列,再结合一下《你不知道的JavaScript》,准备借这篇文章对JS的几道常见的八股题进行总结。其中加入了很多自己的思考,大家也可以参考这篇文章进行复习一下这几道JS的八股。
一、Instanceof 和 typeof的区别是什么
Instanceof 和 typeof 都可以用来判断数据类型是什么,它们的区别如下:
应用场景的区别:
Instanceof 通常是用来判断 引用数据类型(对象)的具体类型,比如判断:
var arr = [1,2,3]; console.log(arr instanceof Array) //truetypeof 通常是用来判断 简单数据类型的具体类型,比如判断:
var str = "Im str"; console.log(typeof str) //string原理的区别:
Instanceof 的原理:
A instanceof B会查找A的原型链 查看是否存在B.prototype,如果存在的话就会返回true,如果直至找到最顶部仍然找不到,则返回false而对于简单数据类型来说(number,string,boolean...)是没有原型链的,所以简单类型使用
instanceof时,始终会返回false,因此instanceof不适合简单数据类型的具体判断。typeof 的原理:
typeof的使用方式是typeof 变量,他对变量类型的判断原理如下:
- 对 简单类型,直接检查值的二进制类型标记,(比如浮点数二进制后的低位类型标记为010)
- 对 引用类型,检查对象是否可调用(函数返回
"function",其他返回"object")。null因历史遗留问题被错误归类为"object"。
拓展:Object.prototype.toString.call()
如果想要准确地识别所有的数据类型,可以用Object.prototype.toString.call() ,它是js中最可靠的数据类型判断方法
对于简单数据类型(Primitive Types):
Object.prototype.toString.call()可以将简单数据类型自动转换成对应的包装数据类型
// 简单类型(Primitive Types)
Object.prototype.toString.call(42); // "[object Number]"
Object.prototype.toString.call("hello"); // "[object String]"
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(Symbol()); // "[object Symbol]"
Object.prototype.toString.call(42n); // "[object BigInt]"
对于引用数据类型(Objct Types):
Object.prototype.toString.call()可以直接判断其对应的类型
// 引用类型(Object Types)
Object.prototype.toString.call({}); // "[object Object]"
Object.prototype.toString.call([]); // "[object Array]"
Object.prototype.toString.call(new Date()); // "[object Date]"
Object.prototype.toString.call(/regex/); // "[object RegExp]"
Object.prototype.toString.call(() => {}); // "[object Function]"
Object.prototype.toString.call(new Map()); // "[object Map]"
Object.prototype.toString.call(new Set()); // "[object Set]"
Object.prototype.toString.call(new Error()); // "[object Error]"
Object.prototype.toString.call(window); // "[object Window]"(浏览器环境)
Object.prototype.toString.call(Math); // "[object Math]"
Object.prototype.toString.call(JSON); // "[object JSON]"
二、为什么typeof null的结果为object?
因为js在早期使用32位方式来存储数据类型,其中前3位表示用作类型标签(比如010表示浮点数)
对于Object,它在转换为二进制后的低位(后三位)为000,而恰好null在转化为二进制后的全为0,因此它的低位也为000
而
typeof 变量在判断时会基于转换后的二进制,所以就导致了typeof null会被JS引擎误判为object。这是一个历史遗留问题,由于后期修复它可能会影响Js的其它部分,所以到现在这个现象仍然存在。
拓展:如何正确判断null
如果想要正确判断null的话:可以使用以下的方法
// 方法1:严格等于
value === null;
// 方法2:Object.prototype.toString(最可靠)
Object.prototype.toString.call(null); // "[object Null]"
// 方法3:组合判断(兼容旧代码)
function isNull(value) {
return value === null || Object.prototype.toString.call(value) === "[object Null]";
}
三、能否手动实现instanceof的功能
手写instanceof的代码如下:
function myInstanceof(left, right) { //基本数据类型直接返回false if(typeof left !== 'object' || left === null) return false; //getProtypeOf是Object对象自带的一个方法,能够拿到参数的原型对象 let proto = Object.getPrototypeOf(left); while(true) { //查找到尽头,还没找到 if(proto == null) return false; //找到相同的原型对象 if(proto == right.prototype) return true; proto = Object.getPrototypeOf(proto); } }
拓展:instanceof能否判断简单数据类型
可以,但是需要我们手写重新实现instance
class PrimitiveNumber {
static [Symbol.hasInstance](x) {
return typeof x === 'number'
}
}
console.log(111 instanceof PrimitiveNumber) // true
这里手写了instance判断 该数据类型是否为number,其中最主要的是static [Symbol.hasInstance](x) { return typeof x === 'number' }:
Symbol.hasInstance 是一个JS内置的 Symbol 值,用于自定义 instanceof 的检查逻辑。当一个构造函数(或 class)定义了 [Symbol.hasInstance] 方法时,instanceof 会调用该方法来判断实例关系。
总结
本文分享的三道八股,可以帮助第一次刷到的人,学习一下对应的知识点,之前刷过的或者接触过的大佬,可以借此复习一下知识点,如果对文章的内容有一些意见以及异议的话,欢迎在评论区指出,创作不易,如果对你有帮助的话,可以点个赞呀!!