一文看懂js中的继承

本文详细阐述了JavaScript中的原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合继承和ES6class继承,探讨了各自的优缺点及适用场景。
摘要由CSDN通过智能技术生成

继承在JavaScript中的应用

JavaScript作为一种动态语言,其继承机制与传统的基于类的编程语言有所不同。在JavaScript中,继承主要通过原型链来实现。本文将详细介绍JavaScript中的各种继承方式,包括原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合继承法以及ES6中的class继承。

1. 原型链继承

原型链继承是JavaScript中最基本的继承方式。在这种继承方式中,每个对象都有一个原型对象,且原型对象包含了所有对象共享的属性和方法。对象可以通过原型链来访问原型对象上的属性和方法。
优点:
简单直观,易于理解和实现。
原型上的属性和方法可以被所有实例共享,节省内存。

缺点:
无法向对象实例添加属性,所有属性和方法都定义在原型上。
父类的属性会被所有实例共享,这意味着修改一个实例的属性会影响到其他实例。

function Parent() {
    this.name = 'Tom';
}

Parent.prototype.like = [1, 2];

function Child() {
    // 子类构造函数
}

// 将子类的原型设置为父类的实例
Child.prototype = new Parent();

2. 构造函数继承

构造函数继承允许子类通过调用父类构造函数来继承父类的属性。这种方式解决了原型链继承中无法继承父类原型方法的问题。
优点:
可以向对象实例添加属性。
父类的属性不会在实例间共享,每个实例都有自己独立的属性。

缺点:
无法继承父类原型上的方法。
每次创建子类实例时,父类构造函数都会被调用,这可能导致性能问题。

function Parent(name) {
    this.name = name;
}

function Child(name) {
    Parent.call(this, name); // 调用父类构造函数
    this.age = 18;
}

let c = new Child('Tom');
console.log(c.name); // Tom

3. 组合继承

组合继承结合了原型链继承和构造函数继承的优点,既能继承父类的属性,又能继承父类原型上的方法。
优点:
结合了原型链继承和构造函数继承的优点,既能继承父类的属性,又能继承父类原型上的方法。
每个实例都有自己独立的属性,同时可以共享父类的方法。

缺点:
父类构造函数被调用了两次,一次在创建子类原型时,一次在子类构造函数中,这可能导致不必要的性能开销。

function Parent(name) {
    this.name = name;
    this.like = [1, 2];
}

Parent.prototype.getName = function() {
    return this.name;
};

function Child(name) {
    Parent.call(this, name);
    this.age = 18;
}

Child.prototype = new Parent(); // 继承父类原型上的方法
Child.prototype.constructor = Child; // 修正constructor指向

let c1 = new Child('Tom');
console.log(c1.getName()); // Tom

4. 原型式继承

原型式继承通过创建一个新对象,并将原型指向父类实例来实现继承。
优点:
创建对象时不需要调用构造函数,可以避免构造函数中的不必要操作。
可以借用另一个对象的属性和方法,而不需要建立原型链。

缺点:
无法继承父类原型上的方法,只能继承对象实例的属性。
无法向子类添加自定义属性或方法。

let parent = {
    name: 'Tom',
    age: 18,
    like: [1, 2, 3]
};

function Child() {
    // 子类构造函数
}

Child.prototype = Object.create(parent); // 设置原型链

5. 寄生式继承

寄生式继承通过创建父类实例的副本,并在此基础上添加新的属性或方法来实现继承。
优点:
避免了父类构造函数被多次调用的问题,提高了性能。
可以向子类添加新的属性或方法。

缺点:
需要手动复制父类的属性和方法,这可能导致代码冗余和维护困难。

var parent = {
    name: "Parent",
    sayName: function() {
        console.log("My name is " + this.name);
    }
};

function createChild(original) {
    var child = Object.create(original); // 创建新对象
    child.age = 18; // 添加新属性
    return child;
}

var child = createChild(parent);

6. 寄生组合继承

寄生组合继承是寄生式继承和组合继承的结合,它解决了组合继承中父类构造函数被调用两次的问题。
优点:
结合了寄生式继承和组合继承的优点,避免了父类构造函数被多次调用的问题,同时继承了父类的属性和方法。
修正了组合继承中父类构造函数被调用两次的问题。

缺点:
代码相对复杂,不如其他继承方式直观易懂。

function Parent(name) {
    this.name = name;
}

Parent.prototype.like = [1, 2];

function Child(name) {
    Parent.call(this, name); // 继承父类属性
    this.age = 18;
}

Child.prototype = Object.create(Parent.prototype); // 继承父类方法
Child.prototype.constructor = Child; // 修正constructor指向

let c1 = new Child('Tom');
console.log(c1); // { name: 'Tom', age: 18 }

7. ES6 class 继承

ES6引入了class关键字,使得JavaScript的继承机制更加接近传统的面向对象编程。
优点:
语法更加简洁和直观,更接近传统的面向对象编程语言。
支持类的继承,使得代码更加模块化和易于维护。

缺点:
需要较新版本的JavaScript环境支持,可能不兼容旧的项目或浏览器。
虽然语法更加简洁,但底层实现仍然是基于原型链,对于不熟悉原型链的开发者来说可能存在理解上的困难。

class Parent {
    constructor(name) {
        this.name = name;
    }

    getName() {
        return this.name;
    }
}

class Child extends Parent {
    constructor(name) {
        super(name); // 调用父类构造函数
        this.age = 18;
    }
}

let c = new Child('Tom');
console.log(c); // { name: 'Tom', age: 18 }
console.log(c.getName()); // Tom

总结

本文详细介绍了JavaScript中的七种继承方式,每种方式都有其适用场景和优缺点。开发者可以根据实际需求和项目特点,选择最合适的继承方式来实现代码的复用和扩展。随着ES6的普及,class继承逐渐成为主流,但在一些旧项目或特定场景下,传统的继承方式依然有其价值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值