1.构造函数
构造函数是用来创建对象的函数,其本质上是一个函数。
2.实例对象
由构造函数创建出来的对象
3.prototype(原型对象)
js规定,每个函数都有一个属性prototype,这个属性是一个对象,这个对象就称为原型对象。
4.__proto__(隐式原型)
每个js对象(null除外)都有一个属性__proto__,这个属性指向该对象的原型对象。
5.constructor(显式原型)
每个原型对象都有一个属性constructor,这个属性指向该原型的构造函数。
//构造函数Gouzhao
function Gouzhao(){}
//构造函数的原型对象Gouzhao.prototype
Gouzhao.prototype.name='构造函数原型对象中的name属性'
//实例对象shiliduixiang
var shiliduixiang = new Gouzhao();
console.log(shiliduixiang.name);//构造函数原型对象中的name属性
shiliduixiang.name='实例对象中的name属性'
console.log(shiliduixiang.name);//实例对象中的name属性
//实例对象的隐式原型shiliduixiang.__proto__,构造函数的原型对象Gouzhao.prototype
console.log(shiliduixiang.__proto__===Gouzhao.prototype);//true
//构造函数Gouzhao的原型对象Gouzhao.prototype的显式原型指向构造函数Gouzhao
console.log(Gouzhao.prototype.constructor===Gouzhao);//true
实例与原型的关系
通过上面代码我们也不难看出,实例对象shiliduixiang中并没有name属性,
但是通过__proto__隐式原型指向构造函数的原型对象Gouzhao.prototype,
所以输出shiliduixiang.name时,输出的是构造函数原型对象中的name属性。
然后我们给shiliduixiang添加name属性后,再次输出的则是shiliduixiang中的name属性。
因为在js中,当读取实例对象的属性时,如果找不到,则会通过__proto__去读取原型对象上的属性,
如果还查不到,就去找原型的原型,一直找到最顶层为止,这种由__proto__构成的关联关系我们称为原型链。
原型链的尽头
前面我们有提到,原型对象本质上是一个对象,既然是对象,就意味着他可以由Object构造函数生成的,
所以原型对象的__proto__指向的是构造函数Object的原型对象,而Object.prototype.__proto__指向null。
所以可以说原型链的尽头是null,所以查找属性的时候查到 Object.prototype 就可以停止查找了。
扩展
下面引用一张经典的原型链图解