阅读须知
本文为个人对原型链的一些理解和感悟,内容可能会有错误,届时还请大家在评论出指出,作者一定积极改正!
简单的实例
function Person(name) {
this.name = name
}
Person.prototype.sayName = function() {
console.log(this.name)
}
let p1 = new Person('aa')
let p2 = new Person('bb')
p1.sayName() // aa
p2.sayName() // bb
这个例子创建了函数对象Person,并添加了name属性,随后在Person的原型上添加了sayName的方法,接下来我们创建了Person的两个实例p1和p2并调用了sayName方法打印了name的值。
这里我们先说一下new Person()到底执行了什么操作,我的理解是这里创建了一个对象,并执行了Person中的语句,this的指向是当前创建的新对象,最后将新的对象赋值给p1。正是这一步绑定了this才让接下来的sayName能打印出值。
这里在浏览器的控制台中打印p1可以看见p1是一个对象,拥有属性name。
p1和p2对象中并没有sayName方法,因此它们调用sayName方法时会从自己的原型链上查找是否有这个方法。
p1实例检查自己没有sayName方法,因此它访问__proto__属性来查找原型上有没有此方法,在本例中是找到的情况,因此调用方法输出name,如果没找到它还会访问原型的__proto__属性继续向上查找,直到__proto__的指向为null为止。
原型链的详细图解
上面的例子中的图只是原型链比较简单的部分,实际上上图可以扩展为下面这样。
规则一、对象的prototype与其实例的__proto__指向相同
规则二、实例没有prototype属性
规则三、对象本身也是一个实例、因此对象也有__proto__属性
规则四、原型链的尽头是Object.prototype指向的null
规则五、所有对象都是函数的实例,因此它们的__proto__指向Fuction.prototype
规则六、函数(Function)本身也是对象,因此它们的__proto__也指向Fuction.prototype
下面我根据旁边总结的规则进行解释:
p1是Person的实例,因此根据规则一p1.__proto__指向Person.prototype。
Person.prototype如果没有经过操作,默认是一个空对象,对象是Object的实例,因此根据规则一Person.prototype.__proto__指向Object.prototype。
Object.prototype.__proto__为了避免原型链死循环会让它指向null保证终止。
Person是通过function Person() {}实例化的,是Function的实例因此根据规则一Person.__proto指向Function.prototype
Object是Function的实例,因此根据规则一Object.__proto指向Function.prototype得到规则五。
Function是特殊的Object,它也是Function的实例,因此根据规则一Function.__proto指向Function.prototype得到规则六。
思考题
至此对原型链的解释已经告一段落了,下面出一个关于prototype的思考题,大家有兴趣的可以在评论区讨论一下。