手写实现typeof和instanceof,并了解原理
最近在和实习生讲这两的原理,并让他们手写实现,他们中间遇到了些困难,此处顺便整理一下
目录:
- 手写实现typeof
- typeof原理解析
- Object.prototype.toString.call 生效原理是什么?
- 递归实现instanceof
- instanceof原理解析
1. 手写实现typeof
实习生会去网上抄答案
function myTypeof(obj){return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();}
但实际上,这并不是typeof,上面的功能,超出了typeof的能力,例如:
typeof [] === 'array' // falsemyTypeof([]) === 'array' // true
我们都知道typeof是判断基本类型的,基本类型有7种: Undefined, null, Boolean, Number, String, bigint, symbol(es6),还能判断出function 然后其他都是object(null是object)
思考:穷举法一一判断是否可取?
- 不可取,没这么多方法
那只能用 Object.prototype.toString.call ,需要做一个map匹配
function myTypeof(params){const type = Object.prototype.toString.call(params).slice(8, -1).toLowerCase()const map = {'number': true,'string': true,'boolean': true,'undefined': true,'bigint': true,'symbol': true,'function': true}return map[type] ? type : 'object'}// 测试用例myTypeof(1)myTypeof('')myTypeof(false)myTypeof(null)myTypeof(undefined)myTypeof(10n) // bigintmyTypeof(Symbol())myTypeof(() => {})myTypeof([])myTypeof({})
typeof原理解析
猜想js的源码肯定不会这么实现(这样有点挫ー ー;)
参考其他的语言,猜想:不同的 基础类型 在内存中都以二进制形式存在,例如:0x00000000。然后为了区分不同的类型会有标识位,比如 (下面的是末位数)
- 000: 对象
- 010: 浮点数
- 100:字符串
- 110: 布尔
- 1: 整数
另外:typeof null 为”object”
- 猜想原因是因为 不同的对象在底层都表示为二进制,在Javascript中二进制前(低)三位都为0的话会被判断为Object类型,null的二进制表示全为0,自然前三位也是0,所以执行typeof时会返回”object”。
举个一个不恰当的例子,假设所有的Javascript对象都是16位的,也就是有16个0或1组成的序列,猜想如下: (末尾数都是 000,会被识别为object)
Array: 1000100010001000null: 0000000000000000typeof [] // "object"typeof null // "object"
为什么Array的前三位不是100?
- 因为二进制中的“前”一般代表低位, 比如二进制00000011对应十进制数是3,它的前三位是011。
2. Object.prototype.toString.call 生效原理是什么?
首先了解一个概念:在js中,一切皆对象。一切皆来自一个”根“原型
- 可以理解成有个“根“原型,创造各类构造函数(包括Object构造函数)。“根“原型类似祖先,在最顶层,在往上就是null
“根”原型 === Object.prototype

Object.prototype.toString.call原理是:
- “根”原型(Object.prototype)下,有个toString的方法,记录着所有 数据类型(构造函数)
- .call作用是改this指向。让传入的对象,执行 “根”原型的toString方法
3. 递归实现instanceof
const myInstanceof = (obj, Fn) => {if (typeof obj !== 'object') return falseconst structure = obj.__proto__if (structure === null) return falseif (structure !== Fn.prototype) {return myInstanceof(structure, Fn)} else {return true}}// 测试用例myInstanceof([], Array) // truemyInstanceof({}, Object) // truemyInstanceof(/1/, RegExp) // trueconst Fn1 = function () {}const a = new Fn1()myInstanceof(a, Fn1) // truemyInstanceof(a, Object) // truemyInstanceof(1, Number) // falsemyInstanceof('', String) // falsemyInstanceof(new String('11'), String) // true
instanceof原理解析
构造函数.prototype(例如 Array.prototype) 可以得到 构造函数的原型
- 构造函数指的是: 例如:Array,RegExp,Object
对象.__proto__(例如:[].__proto__) 也可以得到 构造函数的原型
举例:Array.prototype === [].__proto__ // true
举例:Object.prototype === {}.__proto__ // true
其他的就是递归:如果没找到匹配的,就会递归往上层去找。
- 如果找到,返回true。
- 一直没找到的话,最终会到达null,结束递归,返回false
码字不易,点赞鼓励
