JavaScript实现继承的方式
1、通过原型链继承
让一个构造函数的原型是另一个类型的实例,那么这个构造函数new出来的实例就具有该实例的属性
缺点:对象实例共享所有继承的属性和方法。无法向父类构造函数传参
/*
让一个构造函数的原型是另一个类型的实例,
那么这个构造函数new出来的实例就具有该实例的属性
*/
function Student3(id,name){
this.id = id,
this.name = name,
this.sayhi = function(){
console.log("我叫"+this.name+",id是"+this.id)
} // 静态方法
}
//prototype称为原型,类似java里的static
// Student3.prototype.count =100; //原型变量 -- java里叫静态变量
Student3.prototype.study = function(){
console.log("共享学习空间")
}
function Student( ){}
//让一个构造函数的原型是另一个类型的实例,那么这个构造函数new出来的实例就具有该实例的属性
Student.prototype = new Student3(); //Student 子类, Student3 父类
let student2 = new Student();
student2.id = 10;
student2.name = "张三";
student2.sayhi();
student2.study()
//结果 我叫张三,id是10 共享学习空间
//缺点:对象实例共享所有继承的属性和方法。无法向父类构造函数传参
2、借用构造函数继承
在子类构造函数的内部调用父类的构造函数,使用apply()或call()方法将父对象的构造函数绑定到子对象上
优点:解决了原型链实现继承不能传参的问题和父类的原型共享的问题
缺点:借用构造函数的缺点是方法都在构造函数中定义,无法实现函数复用。在父类型中定义的方法,对于子类型而言是不可见的,结果所有类型都只能使用构造函数模式
/*
在子类构造函数的内部调用父类的构造函数,
使用apply()或call()方法将父对象的构造函数绑定到子对象上
*/
//父类构造函数
function Student3(gender){
this.info = {
id :12,
name :"李四",
age: 13,
gender: gender
}
}
//子类
function Student(gender) {
Student3.call(this,gender);
// Student3.apply(this,id);
}
let student2 = new Student('男');
student2.info.phone = '124263673'
console.log(student2.info);//{id: 12, name: '李四', age: 13, gender: '男', phone: '124263673'}
//优点:解决了原型链实现继承不能传参的问题和父类的原型共享的问题
//缺点:借用构造函数的缺点是方法都在构造函数中定义,无法实现函数复用。
// 在父类型中定义的方法,对于子类型而言是不可见的,结果所有类型都只能使用构造函数模式
3、组合式继承
将原型链和借用构造函数来实现对实例属性的继承.这样,既通过在原型上定义方法实现了函数复用, 又保证在每个实例都有自己的属性
优点:解决了原型链继承和借用构造函数继承造成的影响
缺点:无论什么情况下,都会调用两次父类构造函数:一次是在创建子类原型的时候,另一次是在子类构造函数内部
//3组合式继承
// 将原型链和借用构造函数来实现对实例属性的继承.这样,既通过在原型上定义方法实现了函数复用,
// 又保证在每个实例都有自己的属性
// 父类
function Student3(gender){
console.log('执行次数');
this.info = {
id :12,
name :"李四",
age: 13,
gender: gender
}
}
Student3.prototype.study = function(){ //使用原型链继承原型上的属性和方法
console.log(this.info.id,this.info.name,this.info.age)
}
function Student(gender) {
Student3.call(this,gender); //使用构造函数传递参数
}
Student.prototype = new Student3();
let student2 = new Student("男");
student2.info.phone = "62566273562"
student2.study()
console.log(student2.info)
//结果
/* 执行次数
执行次数
12 '李四' 13
{id: 12, name: '李四', age: 13, gender: '男', phone: '62566273562'} */
//优点:解决了原型链继承和借用构造函数继承造成的影响
/*缺点:无论什么情况下,都会调用两次父类构造函数:
一次是在创建子类原型的时候,另一次是在子类构造函数内部*
4、ES6的class类继承
子类必须在constructor方法中调用super方法,因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。
优点:语法简单。操作方便
缺点:不是所有浏览器都支持class关键字
//Class通过extends关键字实现继承,其实质是先创造出父类的this对象,然后用子类的构造函数修改this
//子类的构造函数中必须调用super()方法,且只有在调用了super()之后才能使用this,
//因为子类的this对象是继承父类的this对象,然后对其加工,而super()方法表示的是父类的构造函数,用来新建父类的this对象
//父类
class Student3{
//方法
constructor(id,name){
this.id = id
this.name = name
}
//方法
getkind(){
return '学号:'+ this.id+',姓名:'+this.name
// return this.kind
}
}
//子类
class Student extends Student3{
constructor(phone){
super(12,'张三');
this.phone = phone;
}
info(){
console.log( super.getkind()+',电话:'+this.phone);
}
}
let student2 = new Student('23676381');
student2.info();