手写源码之 instanceof
手写什么什么的实现,一般是我比较怂的。今天来写一个简单点的,手动实现一次 instanceof 运算符。
instanceof
运算符的作用
既然要手动实现一下 instanceof。那必然是要清楚 instanceof 是什么、能干什么。
MDN上边给的解释是:
❝
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
❞
这里其实是不考虑当前实例对象是否是该构造函数的实例对象,只要能在当前实例对象的原型链上找到该构造函数的原型对象,instanceof 运算符就会返回 true。
看一下实例代码
function Person (name, age) {
this.name = name
this.age = age
}
const person = new Person('向阳', 18)
console.log(person instanceof Person) // true
创建一个构造函数 Person, 然后创建一个 Person 的实例对象 person,此时 person.__proto__ === Person.prototype,所以打印的时候打印出来的是 true。
下面再来看上边提到的另外一种情况:
function Person (name, age) {
this.name = name
this.age = age
}
const obj = {}
obj.__proto__ = Person.prototype
console.log(obj instanceof Person) // true
创建一个空对象 obj,将 obj 的 __proto__ 设置为构造函数 Person 的原型对象。
此时打印出来的也是 true。
这也就是为什么我们经常说的使用 instanceof 判断一个对象是否是一个构造函数的实例对象不准确的原因。就是因为实例对象的原型链是可以被改写的。
好了,说完了 instanceof 的作用之后,接下来就开始动手实现一下叭!
实现
instanceof
话不多说,线上代码再解释!
function Person (name, age) {
this.name = name
this.age = age
}
const person = new Person('向阳', 18)
const obj = {}
// obj.__proto__ = Person.prototype
/**
*
* @param { object } src 实例对象
* @param { function } target 构造函数
*/
function myInstanceof (src, target) {
if (!src || !target) {
console.warn('参数都没传对就来了')
return
}
if (typeof target !== 'function') {
throw Error('target 不是一个构造函数!')
}
let proto = Object.getPrototypeOf(src)
// 也可以用 proto = src.__proto__
const targetProto = target.prototype
while(true) {
if (!proto) return false
if (proto === targetProto) return true
proto = Object.getPrototypeOf(proto)
// 也可以用 proto = proto.__proto__
}
}
console.log(myInstanceof(person, Person)) // true
console.log(myInstanceof(obj, Person)) // false
obj.__proto__ = Person.prototype
console.log(myInstanceof(obj, Person)) // true
创建一个函数 myInstanceof,需要传入两个参数,第一个 src 是实例对象,第二个 target 是构造函数。
首先处理一下参数的问题,防止因为参数没传对而报错。
然后判断一下传进来的 target 是不是一个构造函数,如果不是,那后边就不用玩了。
获取构造函数的原型对象。这里你想用哪种方法都行,Object.getPrototypeOf是 Object 提供的获取对象原型的方法,src.__proto__,则是手动去访问对象的原型,效果是一样的。
拿到构造函数的原型对象 targetProto
写一个 while 循环,因为你不知道要循环多少次,所以循环次数直接设置为 true。
先处理异常情况,如果没有 proto 直接退出循环,并返回 false.
如果存在,判断 proto 和 targetProto 是否相等,如果相等则退出循环,返回 true。
如果不相等,则顺着 src 的原型链,往上接着找 proto 的原型对象,开始下一次循环。
至此,手动实现 instanceof 运算符就讲完啦!
作者:向阳
欢迎关注微信公众号 :大话前端