JS继承的实现方式
首先定义一个父类,代码如下:
//定义一个父类
function Person(name, age, gender){
this.name = name
this.age = age
this.gender = gender
}
//原型方法
Person.prototype.eat = function(food){
console.log(this.name + '正在吃' + food);
}
一、原型链继承
核心:将父类的实例作为子类的原型
//一、原型链继承
function Student(name, age, gender, sno){
this.sno = sno
}
Student.prototype = new Person();
Student.prototype.playing = function(sport){
console.log(this.name + '正在' + sport);
}
let stu1 = new Student('小明',18,'男',123445)
console.log(stu1);
优点:
- 父类新增原型方法或属性,子类都能访问到
- 实例是子类的实例,也是父类的实例
缺点:
二、构造函数继承
核心:利用call复制父类的实例属性给子类
//二、构造函数继承
function Student(name, age, gender, sno){
Person.call(this, name, age, gender)
this.sno = sno
}
let stu2 = new Student('小明',18)
console.log(stu2);
优点:
- 创建子类实例时,可以向父类传递参数
- 可以实现多继承(call多个父类对象)
缺点:
- 只能继承父类的实例属性和方法,不能继承原型属性和方法
- 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
三、实例继承
核心:为父类实例添加新特性,作为子类实例返回
//三、实例继承
function Student(name, age, gender, sno){
let instance = new Person()
instance.name = name
instance.age = age
instance.gender = gender
return instance
}
let stu3 = new Student('小明',18,'男',123445)
let stu3_1 = Student('小明',18,'男',123445)
console.log(stu3);
console.log(stu3_1);
优点:
- 无论是new实例化构造函数还是单纯的独立调用函数,返回的对象具有相同的效果
缺点:
- 实例是父类的实例,不是子类的实例
四、拷贝继承
核心:通过循环拷贝父类属性
//四、拷贝继承
function Student(name, age, gender, sno){
let instance = new Person()
for(let i in instance){
Student.prototype[i] = instance[i]
}
this.sno = sno
}
let stu4 = new Student('小明',18,'男',123445)
console.log(stu4);
优点:
- 支持多继承
缺点:
- 因需要拷贝父类属性导致内存占用高
- 无法获取父类不可枚举的方法
五、寄生式继承
核心:创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回对象。
function createAnother(original,food){
let clone = Object.create(original)
clone.eat = function(food){
console.log(this.name + '正在吃' + food);
}
return clone;
}
function Student(name, age, gender){
let student = {
name,
age,
gender,
playing: function(){
console.log(this.name + '正在打篮球');
}
}
return student;
}
let stu5 = createAnother(Student('小明',18,'男'),'苹果')
console.log(stu5);
六、寄生组合式继承
function Person(name, age, friends){
this.name = name
this.age = age
this.friends = friends
}
Person.prototype.running = function(){
console.log("running");
}
Person.prototype.eating = function(){
console.log("eating");
}
function Student(name, age, friends, sno, score){
Person.call(this, name, age, friends)
this.sno = sno
this.score = score
}
Student.prototype = Object.create(Person.prototype)
Student.prototype.studying = function(){
console.log("studying");
}
let stu1 = new Student('why',18,'张三',1889486,100)
console.log(stu1);
七、ES6实现继承
super()关键字可用于访问父对象上的函数
static关键字:静态方法只能通过类去访问,不能通过实例去访问
class Persons{
static bar(){
console.log('this is bar');
}
constructor(name){
this.name = name
}
//私有方法
say(){
console.log('say function 1111');
}
}
class test extends Persons{
constructor(name, age){
super(name)
this.age = age
}
getage(){
super.say();
}
}
let p = new test('test',18);
p.getage(); //say function 1111
Persons.bar(); //this is bar
console.log(p.bar); //undefined