JavaScript中继承的实现方式
Posted 橘猫吃不胖~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript中继承的实现方式相关的知识,希望对你有一定的参考价值。
javascript中继承的实现方式
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
关键字来继承父类。
以上是关于JavaScript中继承的实现方式的主要内容,如果未能解决你的问题,请参考以下文章