JavaScript中继承的实现方式

JavaScript中继承的实现方式,第1张

JavaScript中继承的实现方式 1 构造函数式继承2 类式继承(原型式继承)3 组合式继承4 寄生式继承5 寄生组合式继承

1 构造函数式继承

构造函数式继承就是在子类中执行父类的构造函数,并为其传递参数,这个过程可以使用call()函数来实现。

示例代码:定义Person类(父类),它有自己的属性name和age,还有自己的方法getName()和getAge()

function Person(name, age) {
    this.name = name; // 初始化姓名和年龄
    this.age = age;
}
Person.prototype.getName = function () { // 获得姓名
    console.log("我的名字" + this.name);
}
Person.prototype.getAge = function () { // 获得年龄
    console.log("我的年龄:" + this.age);
}

接下来定义子类Student,在子类中调用父类的构造函数,获得父类的属性和方法:

function Student(name, age, grade) {
    Person.call(this, name, age); // 将参数传递给父类
    this.grade = grade; // 还可以定义自己的属性
}

但是这样的方式,当初始化子类的对象后,该对象无法获取父类的方法getName()和getAge(),因为父类的方法在原型链上,使用call()方法只获取到了父类本身的环境,并没有获取到父类的原型。

let s1 = new Student("张三", 20, 100);
s1.getName(); // TypeError: s1.getName is not a function
s1.getAge(); // TypeError: s1.getAge is not a function
2 类式继承(原型式继承)

构造函数继承无法继承父类在原型链上的方法,那么类式继承便可以使用父类的方法了。

示例代码:定义Person类(父类),它有自己的属性name和age,还有自己的方法getName()和getAge()

function Person(name, age) {
    this.name = name; // 初始化姓名和年龄
    this.age = age;
}
Person.prototype.getName = function () { // 获得姓名
    console.log("我的名字" + this.name);
}
Person.prototype.getAge = function () { // 获得年龄
    console.log("我的年龄:" + this.age);
}

接下来定义子类Student,子类的原型指向了父类的实例对象,子类的构造函数再指回自己:

function Student(grade) {
    this.grade = grade;
}
Student.prototype = new Person(); // 子类的原型指向父类的实例对象
Student.prototype.constructor = Student; // 子类原型的构造函数再指回子类

类式继承也有一些问题:
①类的原型对象上出现了父类构造函数中的属性和方法,不仅多余,而且是错的。

let s1 = new Student("张三", 20, 100); // 实例化子类
console.log(s1);


②多执行了一次构造函数。如果有很多次继承,那么就会不停地执行构造函数,对资源是一种浪费。

③无法复用构造函数中存储属性的逻辑。子类的属性的初始化与父类没有关系。如果不在子类中初始化name和age,那么就获取不到具体的name和age值,而是显示undefined。

function Student(grade) {
    this.grade = grade;
}
Student.prototype = new Person(); // 子类的原型指向父类的实例对象
Student.prototype.constructor = Student; // 子类原型的构造函数再指回子类

let s1 = new Student("张三", 20, 100);
s1.getName(); // 我的名字undefined
s1.getAge(); // 我的名字undefined
3 组合式继承

组合式继承就是构造函数继承和类式继承的结合,它的问题就是类式继承拥有的问题。

示例代码:定义Person类(父类),它有自己的属性name和age,还有自己的方法getName()和getAge()

function Person(name, age) {
    this.name = name; // 初始化姓名和年龄
    this.age = age;
}
Person.prototype.getName = function () { // 获得姓名
    console.log("我的名字" + this.name);
}
Person.prototype.getAge = function () { // 获得年龄
    console.log("我的年龄:" + this.age);
}

将构造函数式继承和类式继承结合起来实现子类:

function Student(name, age, grade) {
    Person.call(this, name, age);
    this.grade = grade;
}
Student.prototype = new Person(); // 子类的原型指向父类的实例对象
Student.prototype.constructor = Student; // 子类原型的构造函数再指回子类

它的问题如下:
①类的原型对象上出现了父类的构造函数和方法
②多执行了一次构造函数

4 寄生式继承

在一个继承方法中,创建一个寄生类,让寄生类的原型,等于父类的原型,再实例化寄生类,赋值给子类的原型,这叫做寄生式继承。

寄生类代码如下:

function inherit(child, parent) { // 定义寄生类
    function F() {
        this.constructor = child; // 修改构造函数
    };
    F.prototype = parent.prototype; // 寄生类的原型等于父类的原型
    child.prototype = new F(); // 寄生类示例为子类复制
    return child;
}

那么接下来使用一下寄生类,首先定义父类和子类,并且将子类和父类传入寄生类:

// 父类
function Person(name, age) {
    this.name = name; // 初始化姓名和年龄
    this.age = age;
}
Person.prototype.getName = function () { // 获得姓名
    console.log("我的名字" + this.name);
}
Person.prototype.getAge = function () { // 获得年龄
    console.log("我的年龄:" + this.age);
}

// 子类
function Student(name, age, grade) {
    this.name = name;
    this.age = age;
    this.grade = grade;
}

inherit(Student, Person); // 继承

这时创建一个子类的实例对象,查看子类的实例对象,我们发现它解决了组合式继承的问题:①类的原型对象上出现了父类的构造函数和方法;②多执行了一次构造函数

let s1 = new Student("张三", 20, 100);
console.log(s1);


但是它的问题是无法复用构造函数中存储属性的逻辑。与类式继承第③条问题相同。

5 寄生组合式继承

寄生组合式继承就是综合使用构造函数式继承和寄生式继承。在子类中调用一下父类的构造函数。

示例代码:

function inherit(child, parent) { // 定义寄生类
    function F() {
        this.constructor = child; // 修改构造函数
    };
    F.prototype = parent.prototype; // 寄生类的原型等于父类的原型
    child.prototype = new F(); // 寄生类示例为子类复制
    return child;
}

function Person(name, age) {
    this.name = name; // 初始化姓名和年龄
    this.age = age;
}
Person.prototype.getName = function () { // 获得姓名
    console.log("我的名字" + this.name);
}
Person.prototype.getAge = function () { // 获得年龄
    console.log("我的年龄:" + this.age);
}

function Student(name, age, grade) {
    Person.call(this, name, age);
    this.grade = grade;
}

inherit(Student, Person);

寄生组合式继承是ES6之前最好的继承方式了,ES6出现之后使用class关键字来声明一个类,用extends关键字来继承父类。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/web/939719.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-17
下一篇 2022-05-17

发表评论

登录后才能评论

评论列表(0条)

保存