原型继承
核心思路:在子类原型链中加入父类的原型
//定义父类构造函数
function Student(props){ //传入参数为对象,这样的好处是不用按顺序传入参数
this.name=props.name||'UnNamed';
}
//在父类的原型对象上定义方法
Student.prototype.hello=function(){
alert('Hello, '+this.name+'!') //支持es6的话可以用模板字符串
}
//定义子类构造函数
function PrimaryStudent(props){
Student.call(this,props); //调用父类构造函数给实例对象的name赋值
this.grade=props.grade||1; //定义子类对象独有的grade属性
}
//继承函数
function inherits(child,parent){
function F(){}; //定义一个空函数
F.prototype=parent.prototype; //把这个中间函数的原型对象指向父类构造函数的原型对象
child.prototype=new F(); //把子类构造函数的原型对象指向一个新的F对象。
child.prototype.constructor=child; //修复子类构造函数原型对象的constructor属性指向,让它指向子类构造函数
}
//调用继承函数
inherits(PrimaryStudent,Student);
//此时才可以在子类构造函数的原型对象上定义属性和方法
PrimaryStudent.prototype.getGrade=function(){
return this.grade;
}
//创建一个子类构造函数的实例对象
var test=new PrimaryStudent({name:'test'});
//调用父类构造函数原型对象上的方法,看是否成功将父类构造函数的原型对象加入进了子类构造函数的原型链中。
test.hello();
疑难点:
为什么要用一个中间函数加入原型链?直接new Student()不行么?
答:这样的话,子类构造函数创建的实例对象上,会有一堆它并不想继承的父类构造函数上的属性和方法。
Class继承
新的关键字class从ES6开始正式被引入到JavaScrip,它的作用和前面的原型继承一样,但是极大地简化了继承的过程,更加方便。
'use strict';
//父类
class Animal{
//父类构造函数
constructor(name){
this.name=name;
}
}
//子类extends继承父类
class Cat extends Animal{
//子类构造函数
constructor(name){
//调用父类构造函数
super(name);
}
//定义子类独有的方法
say(){
return `hello, ${this.name}!`; //这里用到了es6的模板字符串
}
}