先用一张图来解释一下原型链的结构:
根据上图可以看出,当我们创建一个构造函数Star,这是构造函数就会有一个原型对象,当我们通过构造函数创建一个对象实例之后该对象实例就会有一个属性__proto__指向构造函数的原型对象,除此之外构造函数Star的原型对象也会有一个属性__proto__,这个属性会指向Object原型对象,而Object原型对象会通过constructor属性指向Object构造函数,Object构造函数的原型对象也可以通过属性__proto__来访问,但是此时返回值为null。这一系列的由对象实例通过原型__proto__指向原型对象,在通过原型对象指向Object原型对象这个过程,看起来像一个链状结构,我们称之为原型链。
继承
1)借用父构造函数继承属性
// 父构造函数
function Father(name,age){
this.name = name;
this.age = age;
}
// 子构造函数继承父构造函数属性
function Son(name,age,sex){
Father.call(this,name,age);
this.sex = sex;
}
var person = new Son('丽丽',18,'男');
console.log(person)
结果如下:
我们都知道js中有call(),bind(),apply()可以改变this的指向,这里的继承就是利用call()方法改变了构造函数中this的指向,使得子构造函数this指向父构造函数,这样就可以继承父构造函数的属性了。但是用这个方法只能继承福构造函数的属性,方法继承不了:
// 父构造函数
function Father(name,age){
this.name = name;
this.age = age;
}
Father.prototype.sum = function(){
console.log('计算属性')
}
// 子构造函数继承父构造函数属性
function Son(name,age,sex){
Father.call(this,name,age);
this.sex = sex;
}
var person = new Son('丽丽',18,'男');
console.log(person)
结果如下:和上面的一样,call()方法只能继承父构造函数的属性,不能继承方法。
2)借用父构造函数继承方法
一般情况下我们想的是直接把父构造函数的原型赋予子构造函数的原型,这样可以使得子构造函数继承父构造函数的方法,但是这样也会有一个弊端,那就是当我们修改子构造函数的圆形的时候,父构造函数也会随之改变。
// 父构造函数
function Father(name,age){
this.name = name;
this.age = age;
}
Father.prototype.sum = function(){
console.log('计算属性')
}
Son.prototype =Father.prototype;
// 子构造函数继承父构造函数属性
function Son(name,age,sex){
Father.call(this,name,age);
this.sex = sex;
}
var person = new Son('丽丽',18,'男');
console.log(person)
改变子构造函数之后:
// 父构造函数
function Father(name,age){
this.name = name;
this.age = age;
}
Father.prototype.sum = function(){
console.log('计算属性')
}
Son.prototype =Father.prototype;
Son.prototype.come = function(){
console.log('欢迎仪式')
}
// 子构造函数继承父构造函数属性
function Son(name,age,sex){
Father.call(this,name,age);
this.sex = sex;
}
var person = new Son('丽丽',18,'男');
console.log(person)
console.log(Father.prototype)
这时我们就会看到父构造函数也会有come这个方法,这样就不是很合理,所以这种方法不适用。
我们可以创建一个父构造函数的实例,让子构造函数指向父构造函数的实例,在通过父构造函数的实例指向父构造函数本身,这样子构造函数就可以继承父构造函数的方法了,是通过上面开始讲的原型链完成继承的,这种继承的方法叫做叫做原型链继承。但是这样的话就会改变子构造函数中this的指向,别忘了要用constructor在指向子构造函数,这样就完成了子构造函数继承父构造函数方法
过程图如下:
代码如下:
function Father(name,age){
this.name = name;
this.age = age;
}
Father.prototype.sum = function(){
console.log('计算属性')
}
Son.prototype = new Father(); //
Son.prototype.constructor = Son;
Son.prototype.come = function(){
console.log('欢迎仪式')
}
// 子构造函数继承父构造函数属性
function Son(name,age,sex){
Father.call(this,name,age);
this.sex = sex;
}
var person = new Son('丽丽',18,'男');
console.log(person)
console.log(Son.prototype)
console.log(Father.prototype)
结果如下: