接口与类

TS 中的类

类的组成,定义类通过使用关键字 ‘class’ 进行定义的,后面紧跟的是类的名称,类它包含了以下的几个模块(类的成员)

  1. 字段 - 字段是类里面声明的变量,字段表示对象的字段有关的数据
  2. 构造函数 - 类实例化时被调用,可以为类的对象分配内存
  3. 方法 - 方法为对象要执行的操作
class User {
    1. 字段
    str: string 
    2. 构造函数 
    constructor(str:string) {
        this.u = str
    }
    3. 方法
    sum():void {
        return 
    }
}

类属性和方法的修饰符

在 TS 中,可以使用修饰符对类中的属性和方法进行保护,和构造器的访问,在 TS 中有三个修饰符,修饰类中的属性、方法、构造器

  1. public默认,他代表的是任何创建实例的人都可以一访问到类中的所有内容,类中不书写就是默认使用的是 public,公开的
  2. protected受保护的,他代表的是只有创建他的类内部或者是继承了他的子类,才可以使用这个受保护的属性/方法
  3. private私有的,只能在定义私有属性的类中进行使用

公开的属性

 class Car { 
    1. 字段 
    public engine:string;  // 默认写法,属性以及方法都是公开的外面都可以访问到
 
    2. 构造函数 
    constructor(engine:string) { 
        this.engine = engine 
    }  
 
    3. 方法 
    public disp():void { 
        console.log("发动机为 :   "+this.engine) 
    } 
}

受保护的

所谓的受保护的属性和方法,就是只允许自身定义的类中进行调用,再有就是他有子类,子类继承了父类,子类可以访问父类定义的受保护的属性

class Car { 
  1. 字段 
  protected engine:string;  // 默认写法,属性以及方法都是公开的外面都可以访问到

  2. 构造函数 
  constructor(engine:string) { 
      this.engine = engine 
  }  

  3. 方法 
  public disp():void { 
      console.log("发动机为 :   "+this.engine) 
  } 
}

let hd = new Car('小明')

class Str extends Car {
  public getEngine():void {
    console.log(this.engine);
  }
}

new Str('小红').getEngine()

尝试着在实例类之后,通过实例对象去访问受保护的属性,发现并不能进行访问

私有的

类定义的私有属性和方法,只能通过创建者自身进行调用,通过继承的子类也是不可以访问到的

class Car { 
  1. 私有字段 
  private engine:string;  01 默认写法,属性以及方法都是公开的外面都可以访问到

  2. 构造函数 
  constructor(engine:string) { 
      this.engine = engine 
  }  

  3. 私有方法 
  private disp():void { 
      console.log("发动机为 :   "+this.engine) 
  } 
}

let hd = new Car('小明')

子类继承,修改父类中的属性 & 方法(重写)

使用了修饰符号之后,继承的子类并不是可以随便的修改父类中的属性或者是方法,比如【受保护的 & 私有的】他们比较特殊

  1. 私有的,子类继承父类,但是子类是不可以对父类中任何私有的属性或者是方法进行修改的,并且子类还不能调用父类的方法,如果说在重新定义一个同名的方***不会进行覆盖,答案是错误的,仅切仅有受保护和公开的才可以对方法进行覆盖操作
class Prose {
  private info():void {
    console.log('父类中的方法');
  }
}
class User extends Prose{
  name: string;
  constructor(name:string) {
    super();
    this.name = name;
  }

  public info():void {
    console.log(this.name);
  }
}

let user = new User('子类')
console.log(user.info()); // 子类

如果使用【private : 私有】再次对父类中的info方法进行覆盖是不可以的

!!! 注意:受保护的和私有的修饰,子类是可以覆盖的,但是覆盖父类的方法还是有要求的,比如说父类中的方法是受保护的,但是我们在子类进行覆盖的时候,子类的设置成了私有的方法,这时候是不可以进行覆盖的,会打印错误,但是如果是同级或者是公共的,覆盖是完全没问题的

总结: 子类要想覆盖父类的方法,必须做到要与父类同级或者是比父级修饰符更低级的修饰符,才可以进行覆盖


class User {
  public sum():void {
    console.log(1111);
  }
}
class Str extends User {
  public sum():string {
    return '你好'
  }
}
console.log(new Str().sum());
  1. 重写的概念 类继承后,子类可以对父类的方法重新定义,这个过程称之为方法的重写。

其中 super 关键字是对父类的直接引用,该关键字可以引用父类的属性和方法。

class PrinterClass { 
  doPrint():void {
     console.log("父类的 doPrint() 方法。") 
  } 
} 

class StringPrinter extends PrinterClass { 
  doPrint():void { 
     super.doPrint() 1.  调用父类的函数
     console.log("子类的 doPrint()方法。")
  } 
}

readonly的妙用

他是一个 只读的 一个修饰符,允许你可以访问属性,但是你不能对他进行修改,当然这句话也不是完全正确的,当构造函数初始化的时候,readonly是可以被修改的

class Axios {
  1. 设置只读属性
  readonly stic: string = 'www.baidu.com'

  public get():void {
    console.log( `你的请求地址是${this.stic}` );
  }
}

let axios = new Axios();

console.log(axios.get());
1. 构造函数初始化的时候可以被修改
class Axios {

  readonly stic: string = 'www.baidu.com'

  public constructor(stic?: string) {
    this.stic = stic || this.stic
  }

  public get():void {
    console.log( `你的请求地址是${this.stic}` );
  }
}

let axios = new Axios('www.lagou.com');

console.log(axios.get());

TS 中的构造函数

在 TS 中类的构造函数创建的方式是与JavaScript(原生),有一定的差别,在初始化数据的时候,写法有一些变化

  1. 第一种,你需要在构造函数的外面,先要对属性进行类型的定义,才可以在构造器中访问到
class User {
  public n:string
  public constructor(n:string) {
    this.n = n
  }
  public info():void {
    console.log(this.n);
  }
}
let hd = new User('你好');
hd.info()

Snipaste_2021-10-20_14-40-49.png

  1. 第二种,简便的写法,结合构造函数,一起定义
class User {
  
  public constructor(public n:string) {
    this.n = n
  }
  public info():void {
    console.log(this.n);
  }
}

let hd = new User('你好');

hd.info()

静态属性与方法

静态属性与静态方法,在类中通过 static 关键字进行定义,只能通过类自身进行调用,通过 new 关键字实例化的对象是不可以访问到静态属性与静态方法的

class User {

  static str:string = 'houdunren'

  static info():string {
    return User.str
  }
}

let user = new User()

console.log(User.info());

单例模式

什么是单例模式,所谓的单例模式就是,创建一个类,通过 new 关键字进行实例化,只能实例化一次,多次实例化也只是生产一个对象出来

class Axios {

  private static instance: Axios | null = null

  constructor() {}

  static info(): Axios {
    if(Axios.instance == null) {
      Axios.instance = new Axios();
    }
    return Axios.instance
  }
}

let axios = Axios.info()

抽象类

  1. 抽象类,他是一种规范模板,所有的子类,要想继承 抽象类,他就必须要实现抽象类里面定义的所有内容
  2. 定义抽象类,因为他是一个规范,所以抽象类里面只需要负责定义,它不需要具体的实现
  3. 想要实现抽象类里的内容,就要定义子类继承 抽象类,去实现抽象类中的内容
  4. 抽象类,他不可以被实例化,不可以被 new 关键字实例化出对象
  5. 要想使用抽象方法或者是抽象属性,就必须存在于抽象类当中,并且抽象类也是类他除了不可以通过 new 关键字进行实例化,它自身可以定义方法和属性的。

abstract class AnimationA {

  abstract move(): void 抽象方法
  abstract str: string 抽象属性
  
  protected getPos():number[] {
    return [100,100]
  }
}

class You extends AnimationA {
  
  public str:string = 'you'
  
  public move(): void {
    console.log('你好')
  }
}

class Me extends AnimationA {
  
  public str:string = 'me'
  
  public move(): void {
    console.log('我好');
  }
}

接口

  1. 接口是定义一个规范,接口的内部没有具体的实现,只有规范,它内部不允许出现抽象方法,不允许出现实现方法
  2. 接口通过 interface 去创建一个接口,并且去创建约束条件,并且定义接口名字必须大写,首字母
  3. 使用关键字 implements 去约束某一个类的行为,被约束的类必须实现接口中的规范
interface Adget {
  moeo(): void
}
1. 约束没有继承的类
class Str implements Adget {
  moeo(): void {
    console.log('哈哈哈');
    
  }
}

2. 约束有继承的类
abstract class Animation {

  protected getPos():number[] {
    return [100,100]
  }
}

class You extends Animation implements Adget {
  
  public str:string = 'you'
  
  public move(): void {
    console.log('你好')
  }
}

对象的约束

interface User {
  name: string
  age?:number  1.  可选参数
  info(): void
  [key: string]: any 2.  可以向对象里面添加属性,键的类型必须是字符串,值是任意类型
}

let obj:User = {
  name: 'John',
  age: 34,
  info(): void {
    console.log(this.name + this.age)
  },
  sex: 'male',
  str():void {
    console.log(this.sex)
  }
}

obj.str()
obj.info()

!! 所需要注意的是,在定义接口规范的时候,一个对象自身是可以向对象内部追加属性和方法的,所以在定义接口规范的时候,就需要注意最后一个选项了,这样定义规范的目的是,允许对象,给自身添加属性或者是方法

[key: string] : any

接口之间的继承

接口与接口之间是可以尽心继承的,类实现了User接口的同时,还要去实现Adget的接口规范,通过使用 extends 关键字,实现两个接口之间的继承

interface Adget {
  moeo(): void
}
interface User extends Adget {
  name: string
  age?:number
  info(): void
  [key: string]: any
}

如果不适用关键字 extends 去接口与接口之间的继承,我们也可以使用 ‘逗号’ ,实现一个类实现多个接口的规范,也是可以的

interface Adget {
  moeo(): void
}

interface User {
  name: string
  age?:number
  info(): void
}

class Str implements Adget,User {
  public name: string = 'You';
  public age: number = 18
  public info(): void {
    console.log(this.name + this.age);
  }
  public moeo():void {
    console.log(this.name);
  }
}

let str = new Str();
str.info()

接口约束函数参数

interface User{
  name: string;
  age: number;
}

let obj:User = { 1.  将接口作为对象的类型,来约束对象
  name: '小明',
  age: 20
}

function sum(option: User):User {
  option.name = '小红'
  return option
}

console.log(sum(obj));

接口约束类

interface Us {
  name: string;
  age: number
}

class Str {
  _init: Us; 1. 约束类在传递数据时候,必须传递对象并且要实现接口的规范
  public constructor(n: Us) {
    this._init = n
  }
  public init():Us {
    console.log(this._init);
    return this._init
  }
}

let str = new Str({name: '小明', age:18})
str.init()

接口约束数组


interface User {
  name: string;
  age: number;
}

let arr: User[] = [{  1. 将接口User定义给数组当做类型,并且内部的内容,只能是接口中的内容
  name: '小明',
  age: 10
}]

console.log(arr);

接口声明函数与接口合并

1. 声明一个接口,内部实现的是箭头函数
{

  interface User {
    (n: number): void;
  }

  const _init: User = (n: number) => {
    return n
  }

  _init(5)
}

2. 声明接口,内部实现函数声明,普通函数
{

  interface User {
    (n:number): number;
  }

  let _init: User 

  _init = function (n: number): number {
    return n
  }

  _init(5)
}

简单的介绍一下接口声明合并的问题,我们都知道 JavaScript 里面声明同名的属性后者会覆盖前者,并且将前者的内容更改掉,但是在 TS 里面接口的合并,并不是覆盖的关系,而是合并的关系,假如有一天,你有一个接口内部规范不足以支撑现在的程序,你可以创建一个同名的接口规范,同名的规范之间会进行合并,然后去约束【数组 对象 函数】 等等

type介绍

  1. type 的功能与接口 interface 他们很相似,都是定义规范,然后使用规范去约束对象数组等等。
1. 使用type定义
type User {
	name: string;
	age: number,
	init(): string, 4. 函数类型 
        [key: string]: any 3. 索引类型
}

2. 使用方式

const obj:User = {
	name: '小明',
  age: 18,
  init():string { 2. 函数类型
  	return this.name
  },
  sex: '男' 1. 索引类型,所谓的索引类型,就是可以相对想内可以添加属性,前提是键是‘字符串’
}
  1. type 与 interface 之间的区别,他们之间的最大区别就是 声明 合并的问题,type 与 interface声明合并完全是两个概念,type要想声明合并,他就需要使用 ‘&’ 符号合并,然后通过 type 定义一个新的规范,将合并后的规范赋值给新的规范,用新的规范约束 类、对象、数组等等。
  2. 合并之后,新的 type 声明 是一个联合类型,只要里面其中一个规范实现了,也是没问题的
type User {
	name: string;
}

type Str {
	age: number;
}

type U = User & Str 
  1. 可以使用 implements 关键字,将 type 声明约束类
type User {
	name: string;
}

class Str implements User {
	name:string = '小明'
}
  1. type给基本类型起别名操作
type IsAdmin = boolean

type User {
	bool: IsAdmin // 使用的时候,需要使用别名即可
}

const obj: User = {
	bool: true
}
  1. type 的联合类型声明
type sex = 'boy' | 'girl'

type User {
	sex: sex
}

const obj:User = {
	sex: 'boy' || 'girl'
}
全部评论

相关推荐

11-15 18:39
已编辑
西安交通大学 Java
全村最靓的仔仔:卧槽,佬啥bg呢,本也是西交么
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务