JS面向对象(三)-JS实现继承方式

124 阅读3分钟

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);

image.png

优点:

  1. 父类新增原型方法或属性,子类都能访问到
  2. 实例是子类的实例,也是父类的实例

缺点:

  1. 创建子类实例时,无法向父类构造函数传参
  2. 继承的属性看不到,只会打印对象内可枚举的属性(详细请浏览 JS面向对象(二)
  3. 共享原型会导致数据被改变(详细请浏览 JS面向对象(二)

二、构造函数继承

核心:利用call复制父类的实例属性给子类

 //二、构造函数继承
function Student(name, age, gender, sno){
    Person.call(this, name, age, gender)
    this.sno = sno
}
let stu2 = new Student('小明',18)
console.log(stu2);

image.png

优点:

  1. 创建子类实例时,可以向父类传递参数
  2. 可以实现多继承(call多个父类对象)

缺点:

  1. 只能继承父类的实例属性和方法,不能继承原型属性和方法
  2. 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

三、实例继承

核心:为父类实例添加新特性,作为子类实例返回

 //三、实例继承
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);

image.png

优点:

  1. 无论是new实例化构造函数还是单纯的独立调用函数,返回的对象具有相同的效果

缺点:

  1. 实例是父类的实例,不是子类的实例

四、拷贝继承

核心:通过循环拷贝父类属性

 //四、拷贝继承
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);

优点:

  1. 支持多继承

缺点:

  1. 因需要拷贝父类属性导致内存占用高
  2. 无法获取父类不可枚举的方法

五、寄生式继承

核心:创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回对象。

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);

image.png

六、寄生组合式继承

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);

image.png

七、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