携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情
还记得大一刚接触原型、原型链的概念时整个人像个呆子。后来听了大风老师的画图讲解后我才深刻明白的。授人与鱼,授人与渔。
构造函数、实例、原型三者的关系
任何函数都有一个prototype属性,该属性是一个对象。如下:
function F(){}
console.log(F.prototype)//=>object
F.prototype.sayHi = function(){
console.log("hi!")
}
构造函数的prototype对象默认都有一个constructor属性,指向prototype对象所在的函数。
console.log(F.constructor===F)//=>true
通过构造函数得到实例对象內部都会包含一个只想构造函数的prototype对象的指针__proto__。
var instance = new F();
console.log(instance.__proto__===F.prototype)//=>true;
__proto__是非标准属性
###### 实例对象可以直接访问原型对象成员。
instance sayHi() //=>hi!
我也要向老师当时给我讲的时候一样!画图哈哈!!画图真的很清晰!!不要晕不要晕。看图说话。
以上图示请结合上面几行代码使用。
总结:
- 任何函数都具有一个prototype属性,该属性是一个对象
- 构造函数的prototype对象默认都有一个constructor属性,指向prototype对象所在函数。
- 通过构造函数得到的实例对象內部会包含一个指向构造函数的prototype对象的指针__proto__.
- 所有实例都直接或间接继承了原型对象的成员。
了解了 构造函数-实例-原型对象 三者之间的关系后,接下来我们来解释一下为什么实例对象可以访问原型对象中的成员。
- 每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性。
- 搜索首先从对象实例本身开始。
- 如哦在实例中找到了具有给定名字的属性,则返回该属性的值。
- 如果没找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性。
- 如果在原型对象中找到了这个属性,则返回该属性的值。
也就是说,在我们调用instance.sayHi()时,会先后执行两次搜索:
- 解析器问:“实例instance有sayHi()吗” 答:“没有呜呜呜”
- 然后他继续搜索,再问:“instance的原型里有sayHi()吗” 答:“有!”
- 于是,它就读取那个保存在原型对象中的函数。
如果再次创造实例:
var instanceNew = new F()
console.log(instanceNew.sayHi())//输出什么?
答案还是hi!
无论是instance还是instanceNew去调用本不在自身的方法sayHi(),结果都是一样的,都会进行相同的两次搜索,实现多个对象实例共享原型所保存的属性和方法基本原理。
即:如果在自身找不到,则沿着原型链向上查找,找到就返回;如果一直到原型链的末端还找不到,那就返回“undefined”。
👆,👆,👆,所以宝贝你会了没。
刚刚去关了一下空调,坐在这里长了好冷,我要去恰饭了,goodbye。
锅锅!!11!!!