手写实现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' // false
myTypeof([]) === '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) // bigint
myTypeof(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: 1000100010001000
null: 0000000000000000
typeof [] // "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 false
const structure = obj.__proto__
if (structure === null) return false
if (structure !== Fn.prototype) {
return myInstanceof(structure, Fn)
} else {
return true
}
}
// 测试用例
myInstanceof([], Array) // true
myInstanceof({}, Object) // true
myInstanceof(/1/, RegExp) // true
const Fn1 = function () {}
const a = new Fn1()
myInstanceof(a, Fn1) // true
myInstanceof(a, Object) // true
myInstanceof(1, Number) // false
myInstanceof('', String) // false
myInstanceof(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
码字不易,点赞鼓励