JS中的原型链

在java中,子类继承父类,可以共享父类中的各种属性和方法,又像一个类中的静态变量和静态方法一样
共享给类的所有实例使用,在JS中就是通过原型链的方式使得对象之间共享同一个属性和方法。

什么是原型对象

原型对象是原型链的组成部分,多个原型对象之间链接在一起就像一条链条一样,所以叫原型链,
我们都知道,一个对象都是由其上层的构造函数创建出来的,构造函数与普通函数没什么不同,
只不过使用new关键字调用,即可返回该构造函数的实例对象,一个构造函数当然可以创建多个实例对象
这些对象之间就是通过他们的原型对象实现属性和方法共享的,当然,这些对象的原型对象是同一个对象才
能实现共享,所以原型对象就是使得所有由构造函数创建出来的实例对象可以实现属性和方法共享的对象。
所有实例对象都可以通过__proto__属性访问到它们自身的原型对象。这个属性每一个对象都有,
都说函数也是对象,所有函数中也有该属性。

prototype属性

原型链中搞懂三个属性及其之间的关系,就能搞懂原型链,__proto__属性,prototype属性,
constractor属性,现在说说prototype属性,这个属性是构造函数独有的,其他两个属性,对象和构造函数都有
构造函数的prototype属性是一个对象,该对象就是原型对象,这个对象中的属性和方法共享给由该构造函数
所创建出来的所有实例对象使用。

var Person function(){
    name="万一";
    age=22;
}
Person.prototype.say=function(){
    alert("hello");
}
var a = new Person();
var b = new Person();

这段代码中,我们知道Person是构造函数,也是一个对象,它有prototype属性,也有__proto__,
constructor属性,它的prototype属性是一个原型对象,我们在该原型对象中添加了say方法,
所以a,b这些由构造函数创建出来的实例对象共享该say方法。
其次,函数是对象,但对象并不一定是函数,所以Person.prototype原型对象,a,b实例对象
只有__proto__,constructor属性,没有prototype属性。

从上面例子,我们知道a,b这些实例对象的原型对象是Person.prototype,那Person.prototype原型对象
有没有可能是别人的实例对象呢?当然有!Person.prototype对象是Object构造函数所创建的,
所以Person.prototype的原型对象是Object.prototype,再进一步,Object.prototype原型对象是谁呢?
JavaScript创始人说,你还来劲了是吧,所以规定,Object.prototype的原型对象是null.

ok,我们总结一下,当我们的实例对象获取一个属性或方法时,它会先从自身的构造函数中寻找,
看看自己有没有定义该属性和方法,如果有直接返回,如果没有则去该实例对象的原型对象中寻找,
看看原型对象中有没有该属性,如果有则返回,如果没有则继续往上寻找,这样一层层寻找,是不是像一条链条一样?
这就是原型链的概念,为什么我们没有定义toString方法,实例对象还是有呢?就是我们上面的原型对象定义好了。

最后的最后,看看prototype的样例图吧
prototype

可以看到,prototype是函数独有的属性,Parent构造函数的属性就是Parent.prototype原型对象
从上文我们知道,如果查找需要的属性,实例对象先查看自己构造函数中有没有对应的属性和方法
如果找不到就去该实例的原型对象中找,问题来了,实例对象是怎么跟它的原型对象有联系的呢?

__proto__属性

上文提到过,每个对象都有__proto__属性,函数也是对象,所以函数中也有该属性,通过这个属性
我们的实例对象可以访问到它的原型对象,即按照上图例子,我们可以得到以下结论

p1.__proto__===Parent.prototype	//true
Parent.prototype.__proto__===Object.prototype	//true
Object.prototype.__proto__===null	//true

//因为函数也是对象,任何一个函数或者说对象,都是Function构造函数创建出来的,
//所以任何函数的原型对象都是Function.prototype
Parent.__proto__===Function.prototype	//true
Object.__proto__===Function.prototype	//true

通过__proto__属性,我们的实例对象就可以找到它的原型对象,就是这么简单。下面再看一张图片吧
prototype

从图中可以看到,Parent.prototypeFunction.prototype是同一级别,所以,Parent.prototype
Function.prototype这些对象由Object()创建,也就是Object实例对象
所以这些对象的原型对象就是Object.prototype,即这些对象可以通过__proto__属性访问到
Object.prototype

constructor属性

任何对象都有该属性,函数也有,这个属性指向该对象的构造函数,所以我们有以下结论

p1.constructor===Parent		//true
Parent.prototype.constructor===Parent	//true

//函数也是对象
Parent.constructor===Function;	//true
Object.constructor===Function;	//true

Function构造函数也是一个对象,它的constructor属性指向的是它自己,如下图所示
prototype

总结

prototype属性,由函数指向原型对象,该属性函数独有
__proto__属性,由实例对象指向自己的原型对象,函数和对象都有
constructor属性,由对象指向自己的构造函数,函数和对象都有

原型链复杂在于,什么时候区分函数和对象,一个对象,可以是构造函数,可以是别人的原型对象
也可以是另一个人的实例对象,一个人是你的爸爸,也可以是别人的儿子。大道至简呐,战术后仰~

最后看两张图,好好揣摩一下吧。
prototype

prototype