Appearance
对象继承
一直在说继承,那什么是继承?它有什么作用?如何实现继承?
注意:
面向对象的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。但是在JavaScript中没有类的概念,前边我们说所的类只是我们自己这么叫,大家要清楚。因此它的对象也与基于类的对象有所不同。实际上,JavaScript语言是通过一种叫做原型(prototype)
的方式来实现面向对象编程的。
01.继承的好处
javascript
实现继承最大的好处就是子对象可使用父对象的属性和方法,从而简化了一些代码。
javascript的继承方式一共有六种。
1-1.原型链继承
核心思想:子类型的原型为父类型的一个实例对象 基本做法:
1.定义父类型构造函数
2.给父类型的原型添加方法
3.定义子类型的构造函数
4.创建父类型的对象赋值给子类型的原型
5.将子类型的原型构造属性设置为子类型
6.给子类型原型添加方法
7.创建子类型的对象,可用来调用父类型的方法
案例
javascript
// 定义父类型构造函数
function SupperType() {
this.supProp = 'Supper property';
}
// 给父类型的原型添加方法
SupperType.prototype.showSupperProp = function () {
console.log(this.supProp);
};
// 定义子类型的构造函数
function SubType() {
this.subProp = 'Sub property';
}
// 创建父类型的对象赋值给子类型的原型
SubType.prototype = new SupperType();
// 将子类型原型的构造属性设置为子类型
SubType.prototype.constructor = SubType;
// 给子类型原型添加方法
SubType.prototype.showSubProp = function () {
console.log(this.subProp)
};
// 创建子类型的对象: 可以调用父类型的方法
var subType = new SubType();
subType.showSupperProp();
subType.showSubProp();
缺点
01.原型链继承多个实例的引用类型属性指向相同,一个实例修改了原型属性,另外一个实例的原型属性也会发生变化。
02.不可以传递参数
03.继承单一
1-2.借用构造函数继承
核心思想:使用.call()
和.apply()
方法,将父类构造函数引入子类函数,使用父类的构造函数来增强子类实例,等同于复制父类的实例给子类。
基本做法:
1.定义父类型构造函数
2.定义子类型构造函数
3.给子类型的原型添加方法
4.创建子类型的对象然后调用
PS:
借用构造函数继承的重点就在于SuperType.call(this, name)
,调用了SuperType构造函数,这样,SubType的每个实例都会将SuperType中的属性复制一份。 案例演示
javascript
// 定义父类型构造函数
function SuperType(name) {
this.name = name;
this.showSupperName = function () {
console.log(this.name);
};
}
// 定义子类型的构造函数
function SubType(name, age) {
// 在子类型中调用call方法继承自SuperType
SuperType.call(this, name);
this.age = age;
}
// 给子类型的原型添加方法
SubType.prototype.showSubName = function () {
console.log(this.name);
};
// 创建子类型的对象然后调用
var subType = new SubType("孙悟空", 20);
subType.showSupperName();
subType.showSubName();
console.log(subType.name);
console.log(subType.age);
缺点描述
1.只能继承父类的实例属性和方法,不能继承原型属性和方法。
2.无法实现构造函数的复用,每个子类都有父类实例函数的副本,影响其性能,代码冗余。
1-3.组合继承(重要)
核心思想:原型链继承方式 + 借用构造函数的组合继承
基本做法:
1.利用原型链实现对父类型对象的方法继承
2.利用super()方法借用父类型构建函数初始化相同属性
案例演示:
js
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.setName = function (name) {
this.name = name;
};
function Student(name, age, price) {
Person.call(this, name, age); // 为了得到父类型的实例属性和方法
this.price = price; // 添加子类型私有的属性
}
Student.prototype = new Person(); // 为了得到父类型的原型属性和方法
Student.prototype.constructor = Student; // 修正constructor属性指向
Student.prototype.setPrice = function (price) { // 添加子类型私有的方法
this.price = price;
};
var s = new Student("孙悟空", 24, 15000);
console.log(s.name, s.age, s.price);
s.setName("猪八戒");
s.setPrice(16000);
console.log(s.name, s.age, s.price);
缺点:
1.父类中的实例属性和方法既存在于子类的实例中,有存在于子类的原型中,不过近视内存的占用,因此在使用子类创建实例对象的时候,其原型中会存在两份相同的属性和方法。
注意:
这个方法是js中最常用的继承模式。