类
属性和方法:
1.使用class定义一个类,使用constructor定义构造函数
2.通过new关键字生成新实例的时候,会自动调用构造函数
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age
}
say(): number {
console.log(12);
return 1;
}
}
const test1 = new Person("12", 2);
test1.say()
类的继承:
1.使用extends关键字实现继承,子类中使用super关键字来调用父类的构造函数和方法。
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age
}
say(): number {
console.log(12);
return 1;
}
}
继承person方法类
class Xcy extends Person {
aihao: string;
constructor(name: string, age: number) {
super(name, age);
this.aihao = "打球"
}
}
const xcy_sl = new Xcy("小明",30);
console.log(xcy_sl)
类中的访问修饰符
1. public: 此修饰符代表属性或者方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是public 可省略
class Person {
public name: string;
public age: number;
public constructor(name: string, age: number) {
this.name = name;
this.age = age
}
public say(): number {
console.log(12);
return 1;
}
}
const test = new Person("小明", 123);
test.name="张三"; 允许被修改 √
console.log(test)
2. private:此修饰符的属性或方法是私有的,不能在声明它的类的外部访问。
class Person {
private name: string;
public age: number;
public constructor(name: string, age: number) {
this.name = name;
this.age = age
}
private say(): number {
console.log(12);
return 1;
}
}
const test = new Person("小明", 123);
test.name="30" 错误 属性name为私有属性,只能在类Person里面更改
console.log(test.say()) 错误 say方法为私有方法 只能在类Person内部使用
声明了private的属性或者方法,即使在继承的子类里面,也是无法修改的。
3. protected: 此修饰符的属性或方法是受保护的,它和private类似,区别是它在子类中是允许被访问的
class Person {
protected name: string;
public age: number;
public constructor(name: string, age: number) {
this.name = name;
this.age = age
}
private say(): number {
console.log(12);
return 1;
}
}
const test = new Person("小明", 123);
test.name="30" 错误 属性name为私有属性,只能在类Person或者子类里面更改
console.log(test.say()) 错误 say方法为私有方法 只能在类Person内部或者子类中使用
class TestPerson extends Person {
constructor() {
super("张三", 60);
this.name = "啊啊" 可以使用 因为这是在子类中使用
}
}
4.readonly 此修饰符证明属性是只读的,在constructor中初始化后, 无论是类的内部还是外部 任何地方就不允许再被修改,
class Person {
readonly name: string;
public age: number;
public constructor(name: string, age: number) {
this.name = name; 可以进行一次初始化
this.age = age
}
private say(): number {
console.log(12);
this.name="30" 无法访问name 因为它是只读的
return 1;
}
}
const test = new Person("小明", 123);
test.name 外部可以正常读取 但是不能够进行赋值
5.static 静态成员 静态成员只能通过类访问,它不存在于实例对象中,但是可以通过Person这个类随时访问,不需要一定创建对象使用
class Person {
private _name: string;
age: number;
static ii: number;
constructor(name: string, age: number) {
this._name = name;
this.age = age;
// this.ii ="30"
Person.ii = 60 存在于类名中 不存在本身的对象中
}
set name(name: string) {
this._name = name;
}
}
抽象方法:
1.抽象方法使用abstract关键字修饰。只要类中有一个方法带有此关键字,那么证明整个类都是抽象类。此时类也要加上abstract修饰。
2.定义:抽象类不能够被实例化。用于约束子类,必须要求子类实现那些属性和方法
- 抽象类只能给子类继承, 并且由于是抽象类,所以在继承后,子类必须对抽象类定义好的方法进行重写。
abstract class Person {
age: number;
constructor(name: string, age: number) {
this.age = age;
}
abstract eat(): void;
}
class Demo extends Person {
必须要对抽象类的方法进行实现 因为抽象类定义好的abstract不会进行自动继承
eat() {
}
}
接口 :
1.用来描述类的结构--类似于抽象类 成员必须是公有的,不支持类的修饰符。
2.接口就是用来约束子类 必须拥有某种属性和方法 跟抽象类类似
3.接口名字可以重复 重复的接口将自动合并 而type别名不行
interface Test{
hello:string,
foo():void
}
2.接口的继承
可以多个接口继承
interface Three extends Test,eat{
}
3.使用接口
3.1: 可以使用implements实现接口,与实现抽象类差不多。
如果是这种方式 普通class 那么要将接口内所有的方法和属性全部实现。 否则会报错
class xxx implements Test{}
也可以实现成抽象类 这样不必实现所有方法和属性
abstract class xx implements Test{}
3.2:多态:由继承而产生了不同的类,对同一个方法可以有不同的响应---多态是一个概念,不是某个固定的语法。属于编程思想
interface USB {
start(): void;
run(): void;
end(): void;
}
function demo(u: USB) {
u.start();
u.run();
u.end()
}
class test implements USB {
start() {
console.log('驱动开启')
}
run() {
console.log('正常运行')
}
end() {
console.log('设备驱动卸载')
}
}
demo(new test())
interface test{
age?:number //代表可选属性
}
接口动态属性 不限制属性
interface test2{
[index:number]:string // 代表只需要属性是number 值是任意的string类型就可以了
}
const test:test2 ={ 1:"123" }
- 接口搭配对象使用
interface test{
name:string,
age:number
}
const obj:test = {name:"字符串",age:55}
泛型:
1.在定义函数接口类的时候,先不指定类型,在使用的时候再指定类型。
2.泛型不仅可以用于函数也可以用于接口 类等
T是代表是一个泛型, 也是一个类型,这个类型将来是由调用者决定的,这里是一个形参,可以取任何名字,这里用T作为形参。
function test<T>(name: T): T {
return name
}
使用有泛型的函数 尖括号里面需要具体指定当初定义T时候的类型,可以传入任意类型。 一旦尖括号类型确定,那么传入的实际值就需要和尖括号类型一致
test<number>(1)
2.指定多个泛型参数
function test<T,E>(name: T,age:E): T {
return name
}
test<number,string>(1,"你好")
3.指定默认类型
function test<T=number,E>(name: T,age:E): T {
return name
}
test<number,string>(1,"你好")
- 泛型配合接口使用
function getLenth<T>(arg: T) {
return arg.length 报错 因为arg是一个泛型类型,不确定是什么类型 所以会报错。不能调用length
}
以上的情况 我们可以通过定义一个接口 去约束
interface constraint {
length: number
}
泛型T 继承接口contraint 每次调用的时候 将会检查参数是否包含length属性。
function getLenth<T extends constraint>(arg: T) {
return arg.length
}
getLenth<number>(100) ×
getLenth([1,2]) √
5.泛型配合接口使用
interface constraint<T1, T2> {
length: T1,
age: T2
}
const obj: constraint<number, number> = {
length: 123,
age: 456
}