类
使用class关键字定义,其中包含属性、方法
class Person {
// 定义实例属性
name: string = "John";
// 只读属性
readonly sex: string = "Female";
// 静态属性(类属性),不需要创建对象就可以使用
static age: number = 42;
// 定义方法
sayHello () { console.log("hello!") }
static sayHi () {}
}
const person = new Person();
// 实例属性通过new出的对象调用
person.name = "jack";
// 静态属性,不需要创建对象就可以使用
Person.age = 18
person.sayHello();
Person.sayHi();
构造函数 & this
构造函数,使用constructor关键字创建
class Dog {
name: string;
age: number;
// 构造函数,创建时调用
constructor(name: string, age: number) {
// 这里this表示当前实例,可以通过this向当前对象中添加属性
this.name = name;
this.age = age;
}
// this 表示当前调用方法对象
bark () { alert(this.name + " is a dog"); }
}
const dog1 = new Dog('小灰', 6);
const dog2 = new Dog('小白', 3);
继承 & super关键字
继承
- 使用extends关键字,下面People为父类,Student、Teacher为子类,子类继承父类
- 继承后子类拥有父类所有属性及方法
- 如果子类中有父类中相同的方法,则会覆盖父类中的方法,称为方法重写
super - 在方法中表示当前类的父类
- 如果在子类中写了构造函数,在子类构造函数中必须对父类构造函数进行调用
class People {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello (say: string) { console.log(say + ' Hello~'); }
}
class Student extends People {
// 隐式构造函数,隐式调用super
sayHello () { console.log('say Student~'); }
run () { console.log('run~'); }
}
class Teacher extends People {
sex: string;
constructor(name: string, age: number, sex: string) {
// 如果在子类中写了构造函数,在子类构造函数中必须对父类构造函数进行调用
super(name, age); // 调用父类的构造函数,不调用就会出错,父类参数要写在super中
this.sex = sex;
}
// super表示当前类的父类
sayHello(say: string) { super.sayHello(say); }
}
let s = new Student('jack', 18)
s.sayHello(); // 输出:say Student~
let t = new Teacher('tea', 21, 'male')
t.sayHello('am a teacher'); // 输出:am a teacher Hello~
继承的好处:可以在不修改原来类的前提下,对类进行扩展
OCP原则(开闭原则):对扩展开放,对修改关闭
抽象类
- 以abstract关键字开头的类
- 不能用来创建对象
- 专门用来继承的类
- 可以添加抽象方法,没有方法体,子类必须实现抽象方法
- 可以添加实际的方法和属性
// 不能用来创建对象,只能用来继承
abstract class Car {
name: string;
type: string;
constructor(name: string, type: string) {
this.name = name;
this.type = type;
}
// 定义一个抽象方法
abstract openDoor():void
}
class Bus extends Car{
year: number
constructor(name: string, type: string, year: number) {
super(name, type);
this.year = year;
}
openDoor() {
console.log('openDoor')
}
}
接口
- 接口用来定义类结构,可以同时定义同名多个,以加在一起为准, 定义了一个规范
- 定义包含那些属性和方法,也可以当成一个类型来使用
- 可以在定义类的时候,定义类的结构
- 只能定义对象结构,所有方法都是抽象方法,不能有实际方法和属性
// 和类型相似,也可以当类型声明使用
// 接口可以重复声明,类型不可以
// type myType = { name: string, age: number }
interface myInterface {
name: string;
age: number;
}
interface myInterface {
gender: string
}
let my: myInterface = {
name: '111',
age: 10,
gender: 'male'
}
// 接口中都是抽象方法
// 接口可以定义类时限制类的结构,定义了一个规范
interface MyInter {
name: string;
get name(): string;
set name(name: string);
sayHello(): void;
}
class MyClass implements MyInter {
private name: string;
constructor(name: string) {
this.name = name;
}
get name () { return this.name; }
set name (value: string) { this.name = value;}
sayHello() {}
}
属性的封装
在属性前添加修饰符
- public 任意位置,默认值
- private 私有属性,只能类内部
- protected 当前类和当前类的子类中
class MyClass {
private name: string;
constructor(name: string) {
this.name = name;
}
// 通过类内中添加方法,让属性供外部类访问
getName () { return this.name; }
setName (value: string) { this.name = value;}
}
let mys = new MyClass('aaa')
mys.setName = 'bbb'
console.log(mys.getName)
// 简写
class C {
// 可以直接将属性写在构造函数中,不用写方法体中内容
constructor(public name: string) {}
}
const c: C = new C('aaa');
泛型
泛型,不确定的类型
在定义类或属性时,如果遇到不明确类型可以使用泛型
// <>中可以定义类型,在其中定义了,后面才能使用
function fn<T>(a: T): T {
return a
}
// 直接调用具有泛型的函数
fn(10) // 不指定泛型
fn<string>('1111') // 指定泛型
// 泛型可以指定多个
function fn2<T, K>(a: T, b: K): T {
return a
}
fn2<number, string>(123, 'hello')
// 用接口限制泛型
interface Inter{
length: number;
}
function fn3<T extends Inter>(a: T): number {
return a.length;
}
class MyClss<T> {
name: T;
constructor(name: T) {
this.name = name;
}
}
const mc = new MyClss<string>('jack');