一、类定义时注意的问题
1、类的属性和方法(函数):类可以有属性也没有没有属性,可以有方法也可以没有方法
2、类的属性是放在构造方法中初始化的,若类没有属性,可以不显式定义构造方法,此时,系统会自动生成一个无参的空的构造方法
二、类的继承
(1)父类(基类):可以派生子类的类
(2)子类(派生类):由父类派生而来的类
(1)封装性:对象是属性和行为的封装体 —- 数据安全
(2)继承性:子类可以继承父类的属性和方法 —- 代码复用
(3)多态性:同一个消息传递给不同对象,出现的效果不同 —- 应用灵活、可以适应不同的需求
(1)ES5中继承的实现:没有类的概念
a、构造函数:构造函数名就是类名,在ES5中类的继承实际就是构造函数的继承
b、实现:通过call、apply、bind函数来实现构造函数的继承
<body>
<script>
//ES中通过call、apply、bind来实现构造函数的继承
//基类
function Father(name){
this.name = name
this.age = 30
}
//子类
function Son(name){
//this代表上层对象(window),name参数传递给Father构造函数
Father.call(this,name) //函数劫持,在Son中通过call调用Father构造函数,将参数name传递给Father构造函数
this.height = '178cm'
this.age = 45
this.show = function(){
console.log('姓名:',this.name)
console.log('年龄:',this.age)
console.log('身高:',this.height)
}
}
//从Father继承了name和age
let son = new Son('沸羊羊')
son.show()
</script>
</body>
(2)ES6中的继承:通过关键字extends实现
<body>
<script>
//1.定义父类Fatcher
class Father {
constructor(name, age) {
this.name = name
this.age = age
}
fun() {
console.log('父类')
}
show() {
console.log('姓名:', this.name)
console.log('年龄:', this.age)
}
}
//2.定义子类Son
class Son extends Father {
constructor(name,age) {
super(name,age) //调用父类的构造函数
}
show() {
super.show() //调用父类的show()方法
}
hobby() {
console.log('爱好: 唱、跳、Rap、篮球')
}
}
let s1 = new Son('蔡徐坤','25')
s1.fun()
s1.show()
s1.hobby()
</script>
</body>
4、继承的好处:在父类中定义的属性和方法,子类继承后就可以直接使用。
5、类继承过程中的向上转型:子类对象的类型一定是父类的类型,父类对象的类型不能是子类的类型
(1)typeof:用于判断变量的数据类型(基本数据类型)
typeof 变量名 == ‘数据类型’
(2)instanceof:用于判断变量的数据类型(类类型)
对象名 instanceof 类名
注意
A、super:指向父类。super([参数])表示调用父类的构造函数
B、如果在子类的构造函数中调用父类的构造函数,那么super()必须作为子类构造函数中的第一条语句
在执行子类的构造函数之前必须先执行父类的构造函数(先有父,后有子)
C、方法覆盖(Overwrite):在继承过程中,若父类的某个方法与子类的某个方法同名,则子类方法覆盖父类的同名方法
D、在子类的方法中可以使用super调用父类中的某个方法
E、不允许多继承,只能单继承
多继承:类的直接父类有多个
单继承:类的直接父类只有一个父类
课堂练习1:
(1)定义一个点类(Point),具有x,y两个属性(表示坐标),显示本类信息的show()方法;
(2) 定义一个圆类(Circle)由点类派生,增加一个新的属性半径(radiu),一个计算圆面积的area()方法,和一个同样显示本类信息的show()方法;
(3) 定义一个圆柱体类(Cylinder)由圆类派生,增加一个属性高度(height),一个计算圆柱形体积的方法vol(),一个计算圆柱形表面积的area2()方法,和一个同样显示本类信息的show()方法。
(4)测试:Circle类、Cylinder类的方法
<body>
<script>
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
//坐标
show() {
console.log("x坐标:", this.x);
console.log("y坐标:", this.y);
}
}
class Circle extends Point {
constructor(x, y, radiu) {
super(x, y);
this.radiu = radiu;
}
//圆面积
area1() {
let circle = Math.PI * this.radiu ** 2;
return circle;
}
show1() {
console.log("圆的半径:", this.radiu);
console.log("圆的面积:", this.area1().toFixed(2));
}
}
class Cylinder extends Circle {
constructor(x, y, radiu, height) {
super(x, y, radiu);
this.height = height;
}
//圆柱体积
vol() {
let volume = super.area1() * this.height;
return volume;
}
//圆柱面积
area2() {
let acreage =
//12.57 * 2 + 3.14 * 2 * 2 * 2
super.area1() * 2 + Math.PI * this.radiu * 2 * this.height;
return acreage;
console.log(super.area1())
}
show() {
super.show1();
console.log("圆柱的高:", this.height);
console.log("圆柱的体积:", this.vol().toFixed(2));
console.log("圆柱的面积:", this.area2().toFixed(2));
}
}
let a = new Point("1", "2");
a.show();
console.log("------------------");
let b = new Circle("1", "2", "1");
b.show1();
console.log("------------------");
let c = new Cylinder("1", "2", "2", "2");
c.show();
</script>
</body>