为什么要有原型对象
看到了阮老师的Javascript继承机制的设计思想,明白了当初设计原型对象的历史原因:
- 为了降低JavaScript的学习难度,所以不引入
类(class)的概念 
- 构造函数使用
new运算符实例化对象后,并不能共享属性和方法,这一点不利于之后的继承
大概基于以上两点,Brendan Eich决定给构造函数设置一个prototype属性。 
原型对象
每一个构造函数都有一个prototype的属性,这个属性指向的一个对象,而这个对象就是原型对象。对于每一个实例化的对象而言,可以通过__proto__属性访问到其构造函数的prototype对象。按自己理解来说:每一个Function都有一个prototype属性,而该属性指向的就是原型对象,而原型对象上的作为一个公共区域,实例化的对象就可以访问到其构造函数的原型上的属性和方法。
举例说明
1 2 3 4 5 6 7 8 9 10 11 12 
  | function Person(name,age){     this.name = name;     this.age = age;     this.sayName = function(){         console.log(this.name)     } } let p1 = new Person("baiji",10) let p2 = new Person("baixiaoji",20) console.log( baiji.sayName === baixiaoji.sayName )   
  | 
 
如果按照上述的代码,每一次实例化对象的时候,都要创建一个sayName的函数,如果要构造1000个Person的实例,那么内存一定会吃紧,所以prototype属性就可以将构造函数的公共的属性和方法都放上去。改写上述的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 
  | function Person(name,age){     this.name = name;     this.age = age; } Person.prototype.sayName = function(){     console.log(this.name) } let p1 = new Person("baiji",10) let p2 = new Person("baixiaoji",20) console.log( p1.sayName === p2.sayName )   class Person{          constructor(name,age){         this.name = name         this.age = age       }     sayName(){         console.log(this.name)     } } 
  | 
将公共的方法抽取出来,挂在prototype上,可以供实例化的对象调用公共方法。
文字说明
Person是一个构造函数,通过new可以构造出Person的一个实例对象(p1、p2),每一个对象都会有一个__proto__的属性指向构造函数的原型对象(Person.prototype)。每一个函数都会一个prototype的方法,指向一个对象;而每一个原型对象(Person.prototype)都有一个constructor指向这个函数本身(Person())。
大概关系如下图:

这也就可以解释了,为什么每一个对象上都有一个toString的方法,见下图:

这样指向一层又一层的原型对象(会有终止),就是JavaScript的原型链,而我们可以基于原型链的特性,实现之后的继承。
继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 
  | function Person(name,age){     this.name = name;     this.age = age; } Person.prototype.sayName = function(){     console.log(this.name) } function Worker(name,age,workYear){     Person.call(this,name,age)     this.workYear = workYear } inherit(Person,Worker) Work.prototype.sayWork = function(){     console.log(this.work) } function inherit(superType, subType){              Object.create  创建一个拥有指定原型和若干指定属性的对象  有兼容问题          这个实现的好处:防止对子类的原型对象修改的时候,修改到了父类的原型对象上     */     let __prototype = Object.create(superType.prototype)     __prototype.constructor = subType      subType.prototype = __prototype } let p1 = new Work("baiji",10,"学生") 
  | 
 
其实JavaScript中的继承是通过原型链的方式,实现了继承父类的方法和属性。由此,就是原型拓展的全部,知道了上面这些知识点,我们就可以去根据面向对象的方式去封装一些组件。
总结
- 每一个构造函数都有一个
prototype属性,指向其原型对象,一般将公共的方法和属性挂在上面 
- 由new运算符实例化的对象,通过
__proto__属性访问其构造函数的原型对象 
- JavaScript通过
原型链的方式实现继承