JavaScript的八种继承方法

常用七种ES5继承方案和ES6的类继承共八种继承方法。

1、原型继承

把子类的原型指向要继承的父类

//父类
function ParentClass(name) {
    this.name = name
}
ParentClass.prototype.eatName = 'xx';
ParentClass.prototype.eat = function (name) {
    console.log('这是一个' + name);
};
//子类
function ChildClass(age) {
    this.age = age
}

/* 将 ChildClass 的原型直接赋值为 ParentClass的构造函数,
    所以此时ChildClass的原型对象中的 constructor其实是指向ParentClass的构造函数的,
    所以我们这边要修改回来,不然引起原型链的絮乱 */
ChildClass.prototype = new ParentClass();
ChildClass.prototype.constuctor = ChildClass;
let obj = new ChildClass('12', 22);
obj.eat('西红柿');
console.log(obj.eatName); // xx

缺点:只能继承父类原型上的方法和属性,不能继承父类的实例属性和方法,多个实例对引用类型的操作会被篡改。

2、构造函数继承

使用parentClass.call(this)改变this的指向来调用父类的属性和方法

//父类
function ParentClass(name) {
    this.name = name;
    this.eat = function(){
        console.log('这是一个' + name);
    }
}

//子类
function ChildClass(name,age) {
    ParentClass.call(this,name)
    this.age = age
}

let obj = new ChildClass('西红柿', 22);
console.log(obj.name,obj.age);
obj.eat() // 这是一个西红柿

缺点:只能继承父类实例e的属性和方法,不能继承原型上的属性和方法

 3、组合式继承

以上二种继承方式的组合

//父类
function ParentClass(name) {
    this.name = name;
}
ParentClass.prototype.eatName = 'xx';
ParentClass.prototype.eat = function () {
    console.log('这是一个' + this.name);
};
//子类
function ChildClass(name,age) {
    ParentClass.call(this,name)
    this.age = age
}
/* 
    将 ChildClass 的原型直接赋值为 ParentClass的构造函数,
    所以此时ChildClass的原型对象中的 constructor其实是指向ParentClass的构造函数的,
    所以我们这边要修改回来,不然引起原型链的絮乱 
*/
ChildClass.prototype = new ParentClass();
ChildClass.prototype.constuctor = ChildClass;
let obj = new ChildClass('西红柿', 22);
console.log(obj.name,obj.age);
obj.eat() // 这是一个西红柿

 4、原型式继承

利用Object.creat(parentClass)创建一个原型指向parentClass的对象

let parentClass = {
    name: '西红柿'
};
let ChildClass = Object.create(parentClass);
ChildClass.age = 11;
console.log(ChildClass.name,ChildClass.age); //西红柿 11

缺点:无法传递参数,原型链继承多个实例时,实例引用类型指向相同,存在篡改的可能

5、寄生式继承

在原型上的基础上新增属性和方法增强函数

let parentClass = {
    name: '西红柿'
};

function clone(original){
    let obj = Object.create(original);
    obj.eat = function(){
        console.log('这是一个' + this.name); //西红柿
    }
    return obj;
}

let ChildClass = clone(parentClass);
console.log(ChildClass.name);
ChildClass.eat();

缺点:(同上原型式继承)无法传递参数,原型链继承多个实例时,实例引用类型指向相同,存在篡改的可能

6、寄生组合式继承

将组合式和寄生式结合起来

//父类
function ParentClass(name) {
    this.name = name;
}
ParentClass.prototype.eat = function () {
    console.log('这是一个' + this.name);
};
//子类
function ChildClass(name,age) {
    ParentClass.call(this,name)
    this.age = age
}

/* 
    这里改用 Object.create 就可以减少组合继承中多进行一次构造的过程
*/
ChildClass.prototype = Object.create(ParentClass.prototype);
ChildClass.prototype.constuctor = ChildClass;

let obj = new ChildClass('西红柿', 22);
    obj.eat();
    console.log(obj.age); // 22

 目前最成熟的方法

7、混入方式继承多个对象

在寄生组合方法中的Object.creat()的下一行使用Object.assin()混合其它的类,

Object.assin()会把所有可枚举的属性从一个或多个原对象复制到目标对象。

//父类
function ParentClass(name) {
    this.name = name;
}
ParentClass.prototype.eat = function () {
    console.log('这是一个' + this.name);
};

function ParentClass1(count) {
    this.count = count;
}
//子类
function ChildClass(name,age,count) {
    ParentClass.call(this,name);
    ParentClass1.call(this,count);
    this.age = age
}

/* 
    这里改用 Object.create 就可以减少组合继承中多进行一次构造的过程
*/
ChildClass.prototype = Object.create(ParentClass.prototype);
//混合其它
Object.assign(ChildClass.prototype,ParentClass1.prototype)
ChildClass.prototype.constuctor = ChildClass;

console.log(ChildClass);
let obj = new ChildClass('西红柿', 22, 10);
    obj.eat();
    console.log(obj.age,obj.name,obj.count); // 22

 8、ES6类继承

用extends继承父类,在子类的construtor调用super()。

//父类
class ParentClass {
    constructor(name){
        this.name = name
    }
    eat(){
        console.log('这是一个' + this.name);
    }
}

//子类
class ChildClass extends ParentClass{
    constructor(name,age){
        super(name)
        this.age = age
    }
}

let obj = new ChildClass('西红柿', 22);
    obj.eat();
    console.log(obj.name,obj.age); // 西红柿 22

ES5继承和ES6继承的区别:

ES5:先创建子类的实例对象,再把父类的属性和方法添加到this上。

ES6:先创建父类的实例对象this,再用子类的构造函数修改this。因为子类没有自己的this,所以必须调用父类的super()方法,否则新建实例会报错

posted @ 2022-10-20 22:08  雪旭  阅读(1897)  评论(0编辑  收藏  举报