被要求实现instanceof,面试官到底在考我什么?
也许你我素未谋面,但很可能相见恨晚,我是前端胖头鱼
被问麻了
相信小伙伴面试时不止一次被要求手写实现xxx了,曾经胖头鱼也被问过n次类似问题,其中有一个题目映像比较深刻,
instanceof实现原理
,这篇文章我想和大家一起尝试用至少3种方式实现...
胖头鱼的手写实现仓库(350 star),你要的手写都有,欢迎点击看看
用法回顾
instanceof
运算符用于检测构造函数的prototype
属性是否出现在某个实例对象的原型链上。MDN上
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);
console.log(auto instanceof Car);
// expected output: true
console.log(auto instanceof Object);
// expected output: true
原型链回顾
原型、原型链是实现
instanceof
最重要的知识点,这里简单回顾一下,推荐两篇写的很好的文章。
请看图:
1. f是Fo的实例对象,它会有一个__proto__属性指向Fo的原型prototype
2. Fo继承自Foo,其prototype是Foo的实例,会有一个__proto__属性指向Foo的的原型prototype
3. Foo继承自顶层对象Object,其prototype是Object的实例,会有一个__proto__属性指向Object.prototype
4. Object.prototype已经是最顶层的对象,其__proto__属性指向null
代码示例
const Foo = function (name, sex) {
this.name = name
this.sex = sex
}
Foo.prototype.showName = function () {
console.log(this.name)
}
const Fo = function (name) {
Foo.call(this, name)
}
Fo.prototype = Object.create(Foo.prototype)
const f = new Fo('前端胖头鱼')
f.showName() // 前端胖头鱼
三种实现方式
要实现instanceof
本质上只要只要遍历实例对象的原型链,挨个往上查找看是否有与Fn的prototype
相等的原型,直到最顶层Object
还找不到,那么就返回false,否则结果就是true
关键点:
- 构造函数
Fn的prototype
- 实例对象的原型链
递归实现(方式1)
/**
*
* @param {*} obj 实例对象
* @param {*} func 构造函数
* @returns true false
*/
const instanceOf1 = (obj, func) => {
// 必须是对象或者函数
if (!(obj && ['object', 'function'].includes(typeof obj))) {
return false
}
let proto = Object.getPrototypeOf(obj)
if (proto === func.prototype) {
return true
} else if (proto === null) {
return false
} else {
return instanceOf1(proto, func)
}
}
// 测试
let Fn = function () { }
let p1 = new Fn()
console.log(instanceOf1({}, Object)) // true
console.log(instanceOf1(p1, Fn)) // true
console.log(instanceOf1({}, Fn)) // false
console.log(instanceOf1(null, Fn)) // false
console.log(instanceOf1(1, Fn)) // false
遍历实现(方式2)
/**
*
* @param {*} obj 实例对象
* @param {*} func 构造函数
* @returns true false
*/
const instanceOf2 = (obj, func) => {
// 必须是对象或者函数
if (!(obj && ['object', 'function'].includes(typeof obj))) {
return false
}
let proto = obj
while (proto = Object.getPrototypeOf(proto)) {
if (proto === func.prototype) {
return true
}
}
return false
}
// 测试
let Fn = function () { }
let p1 = new Fn()
console.log(instanceOf2({}, Object)) // true
console.log(instanceOf2(p1, Fn)) // true
console.log(instanceOf2({}, Fn)) // false
console.log(instanceOf2(null, Fn)) // false
console.log(instanceOf2(1, Fn)) // false
遍历实现(方式3)
/**
*
* @param {*} obj 实例对象
* @param {*} func 构造函数
* @returns true false
*/
const instanceOf3 = (obj, func) => {
// 必须是对象或者函数
if (!(obj && ['object', 'function'].includes(typeof obj))) {
return false
}
let proto = Object.getPrototypeOf(obj)
// 因为一定会有结束的时候(最顶层Object),所以不会是死循环
while (true) {
if (proto === null) {
return false
} else if (proto === func.prototype) {
return true
} else {
proto = Object.getPrototypeOf(proto)
}
}
}
// 测试
let Fn = function () { }
let p1 = new Fn()
console.log(instanceOf3({}, Object)) // true
console.log(instanceOf3(p1, Fn)) // true
console.log(instanceOf3({}, Fn)) // false
console.log(instanceOf3(null, Fn)) // false
console.log(instanceOf3(1, Fn)) // false
最后
希望能一直给大家分享实用、基础、进阶的知识点,一起早早下班,快乐摸鱼。
转载自:https://juejin.cn/post/7075852383250546718