被问麻了

相信小伙伴面试时不止一次被要求手写实现xxx了,曾经胖头鱼也被问过n次类似问题,其中有一个题目映像比较深刻,instanceof实现原理,这篇文章我想和大家一起尝试用至少3种方式实现…

胖头鱼的手写实现仓库(350 star),你要的手写都有,欢迎点击看看

github.com/qianlongo/f…

用法回顾

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最重要的知识点,这里简单回顾一下,推荐两篇写的很好的文章。

image.png

请看图:

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() // 前端胖头鱼

image.png

三种实现方式

要实现instanceof本质上只要只要遍历实例对象的原型链,挨个往上查找看是否有与Fn的prototype相等的原型,直到最顶层Object还找不到,那么就返回false,否则结果就是true

关键点:

  1. 构造函数Fn的prototype
  2. 实例对象的原型链

递归实现(方式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

最后

希望能一直给大家分享实用、基础、进阶的知识点,一起早早下班,快乐摸鱼。