类:构造函数的语法糖
类: 面向对象中,将下面对一个对下面所有成员的定义,统称为类。
传统的构造函数的问题
- 属性和原型方法定义分离,降低了可读性。 --> 就是说: 如果你在构造函数和方法之间写了一千行其它的代码,将他们分隔得太远,不便于阅读。
- 原型成员可以被枚举到。 --> 一般来说,我们枚举的一般是对象的属性,而构造函数的方法不希望被枚举到,但是 es5 是会被枚举到的。
- 默认情况下,构造函数仍然可以当作普通函数使用。
类的特点
- 类申明不会被提升,与 let 和 const 一样,存在暂时性死区。 --> 也就是说在类之前就调用类是会报错的。
- 类中的所有代码均在严格模式下执行。
- 类的所有方法都是不可枚举的。
- 类的所有方法都无法被当作构造函数使用。 --> 但是 es5 是可以的,所以不严谨。
- 类的构造器必须使用 new 来调用
类的其它书写方式
- 可计算的成员名
const className = "hnx";
class Animal {
constructor(type, name, age, sex) {
// 构造器
this.type = type;
this.name = name;
this.age = age;
this.sex = sex;
}
[className]() {
// 可计算的成员名
console.log(`【类型:】${this.type}`);
console.log(`【名字:】${this.name}`);
console.log(`【年龄:】${this.age}`);
console.log(`【性别:】${this.sex}`);
}
}
const animal = new Animal("狗", "旺财", 5, "男");
animal[className](); // 能执行
-
getter 和 setter
-
静态成员 static
- 构造函数本身的成员,不代表原型上的
class Test {
constructor() {}
change() {
console.log("change");
}
static staticChange() {
console.log("staticChange");
}
}
var test = new Test();
test.change(); // change
Test.staticChange(); //staticChange
test.staticChange(); // 报错,test staticChange is not a fn
- 字段初始化器 (ES7)
- 注意:
- 使用 static 的字段初始化器,添加的是静态成员,并且实例访问不到,只能是类本身才能访问到。
- 没有使用 static 的字段初始化器,添加的成员位于对象上 (特别注意)
- 箭头函数在属性初始化器位置上,指向当前对象。 但是这样写的缺点: 这个方法现在在这个对象上面,相当于每一次创建都会创建一个 print 方法,会占用额外的内存空间。
class Test{
static a = 1
b = 2
c = 3
------上面那样es7写相当于下面es6----------
constructor() {
this.b = 2
this.c = 2
}
static a = 1
}
-
类表达式 const A = class {// 匿名类 }
-
[扩展]装饰器 (ES7:现在还不是很支持) (Decorator: 装饰器, 如果类里面的很多方法快要过期了,要有个提示,如果一个一个方法去改的话会比较 low,但是现在可以有一个方法,来标记这个方法过没过期..)
class Test {
@Obsolete //标记: 可以自定义命名,这儿命名的代表过期
print() {
console.log("print方法");
}
}
function Obsolete(target, methodName, descriptor) {
console.log(target, methodName, descriptor);
}
类的继承
如果两个类 A 和 B,如果可以描述为: B 是 A ,则 A 和 B 形成继承关系。
如: 猫是动物,猫继承动物
- 如果 B 是 A,则:
- B 继承 A
- A 派生 B
- B 是 A 的子类
- A 是 B 的父类
如果 A 是 B 的父类,则 B 会自动拥有 A 中的所有实例成员。
新的关键字:
- extends: 继承,用于类的定义
- 用法: Dog extends Animal (类 Dog 的原型继承类 Animal 的原型)
- super
- 直接当作函数调用,表示父类构造函数
- 如果当作对象调用,表示父类的原型
注意: ES6 要求,如果定义了 constructor,并且该类是子类,则必须在 constructor 的第一行手动调用父类的构造函数。
如果子类不写 constructor, 则会有默认的构造器,改构造器需要的参数和父类一致,并且会自动调用父类构造器。
【冷知识】
- 用 JS 来模拟抽象类的概念
- 抽象类: 一般是父类,不能通过该类创建对象(也就是说: 动物是一个抽象类,它不属于任何,只能说有狗,有猫,但没有动物这个东西,所以理应不能 new 这个类)
网友评论