一、接口

1、定义

【接口】是对象的状态(属性)和行为(方法)的抽象(描述)。接口是一种类型,是一种规划、约束。

        接口中可以将数组的索引值和元素设置为不同类型,索引值可以是数字或字符串

        注意接口不能转换为 JavaScript。 它只是 TypeScript 的一部分。

2、属性

【属性】readonly:只读属性、?:可选属性

interface IPerson {
  readonly id: number  //只读属性
  name: string
  age: number
  sex?: string  //可选属性
}

const person1: IPerson = {
  id:1,
  name: 'tom',
  age: 20,
  // sex: '男' // 可以没有
  // xxx: 12 // error 没有在接口中定义, 不能有
}
person1.id = 2 // error
3、函数类型

【函数类型】为了使用接口表示函数类型,我们需要给接口定义一个调用签名。它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型。

// 为了使用接口表示函数类型,我们需要给接口定义一个调用签名

((() => {
// 函数类型:通过接口的方式作为函数的类型来使用
interface ISearchFunc {
// 定义一个调用签名,只有参数列表和返回值类型的函数定义,参数列表的每个参数都需要名字和类型
        (source: string, subString: string): boolean
    }
// 定义一个函数,该类型就是上面定义的接口
const searchString: ISearchFunc = function (source: string, subString: string): boolean {
return source.search(subString) > -1
    }
// 调用函数

console.log(searchString("hello", "e"))  //true
console.log(searchString("hello", "y"))  //false
}))()
4、类类型

【类类型】类的类型可以通过接口来实现。

接口和接口之间叫继承(extends),类和接口之间叫实现(implements )

类可以实现1个或多个接口,接口可以继承其他的多个接口,继承的各个接口使用逗号分隔。

// 类 类型:类的类型可以通过接口来实现
(() => {
interface IFly {
fly(): any
    }
// 类可以同时实现1个或多个接口
class Person1 implements IFly {
fly() {
console.log("我会飞了")
        }
    }
// 实例化对象
const person1 = new Person1()
person1.fly() //我会飞了
interface IRun {
run(): any
    }
// 类可以同时实现1个或多个接口
class Person2 implements IRun, IFly {
run() {
console.log("我会跑了")
        }
fly() {
console.log("我会飞了")
        }
    }
const person2 = new Person2
person2.run() //我会跑了
person2.fly() //我会飞了

// 定义一个接口,继承其他的多个接口
interface IFlyAndRun extends IFly, IRun { }
class Person implements IFlyAndRun {
fly() {
console.log("我会飞了")
        }
run() {
console.log("我会跑了")
        }
    }
const person = new Person()
person.fly() //我会飞了
person.run() //我会跑了
// 总结:接口和接口之间叫继承(extends),类和接口之间叫实现(implements )
// 类可以实现1个或多个接口,接口可以继承其他的多个接口
})()
5、接口和类型别名对比
interface IPerson {
    name: string;
    age: number;
    sayHi(): void
}
let mike: IPerson = {
    name: "mike",
    age: 12,
    sayHi() { }
}
type IPerson1 = {
    name: string;
    age: number;
    sayHi(): void
}
let mike1: IPerson1 = {
    name: "mike",
    age: 12,
    sayHi() { }
}

type 关键字(可以给一个类型定义一个名字)多用于复合类型

type 和 interface 相同点:都可以给对象定义类型

不同点:

(1)interface可以继承(使用extends关键字),type 只能通过 & 交叉类型合并

(2)接口只能为对象指定类型; 类型别名不仅可以为对象指定类型,实际上可以为任意类型指定别名

(3)type 可以定义 联合类型 和 可以使用一些操作符, interface不行

(4)interface 遇到重名的会合并, type 不行

(5)同名属性不同类型冲突处理方式:接口会存在类型不兼容错误;交叉类型不会报错,会处理为联合类型。??

interface IA {
    name: string;
}
interface IB extends IA {
    name: number
}

6、接口继承
//接口继承
interface Point2D { x: number; y: number }
interface Point3D extends Point2D { z: number }
let p3: Point3D = { x: 1, y: 4, z: 9 }

二、类

1、定义

【类】类描述了所创建的对象共同的属性和方法,类可以理解为模板,通过模板可以实例化对象。类包含成员、构造函数、方法

使用new构造类Person的实例对象p1,它会调用之前定义的构造函数,创建一个类Person的新对象,并执行构造函数初始化它。通过p1对象调用类中的方法。

(() => {
class Person {
// 定义属性
name: string
age: number
// 定义构造函数
constructor(name: string = "Mike", age: number = 22) {
this.name = name,
this.age = age
        }
// 定义实例方法
sayHi(str: string) {
console.log(`大家好,我是${this.name},我今年${this.age}岁了`, str)
        }
    }
const person = new Person("Lisa", 11)
person.sayHi("你们好") //大家好,我是Lisa,我今年11岁了 你们好
})()
2、继承

【继承】类和类之间的关系:子类(派生类)继承基类(超类、父类);子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。

      注意:Ts中 ,子类只能继承一个父类,不支持继承多个父类,但支持多重继承(A 继承 B,B 继承 C)。

3、重写

【重写】 类继承后,子类可以对父类的方法重新定义,这个过程称之为方法的重写。子类可以使用super调用父类的构造函数、实例方法。子类中可以重写父类的方法。

// 类:可以理解为模板,通过模板可以实例化对象
// 面向对象的编程思想
// 继承:类和类之间的关系 子类(派生类)继承基类(超类、父类)
(() => {
// 父类
class Person {
name: string
age: number
// 定义构造函数
constructor(name: string = "大大", age: number = 34) {
this.name = name
this.age = age
        }
// 定义实例方法
sayHi(str: string) {
console.log(`我是${this.name}`, str)
        }
    }
// 子类
class Student extends Person {
// 定义构造函数
constructor(name: string, age: number) {
// 使用super调用父类的构造函数
super(name, age)
        }
// 定义实例方法
sayHi() {
console.log("我是学生类中的sayHi方法")
super.sayHi("调用父类中的sayHi方法")
        }
    }

const person = new Person()
person.sayHi("哈哈")  //我是大大 哈哈
const student = new Student("小小", 12)
student.sayHi() //我是学生类中的sayHi方法 我是小小 调用父类中的sayHi方法

// 总结:子类(派生类)继承(extends)基类(超类、父类),
// 子类可以使用super调用父类的构造函数、实例方法,
// 子类中可以重写父类的方法
})()
4、多态

【多态】父类型的引用指向子类型的对象,不同类型的对象针对相同的方法,产生了不同的行为。

// 多态:父类型的引用指向子类型的对象,不同类型的对象针对相同的方法,产生了不同的行为
(() => {
// 定义一个父类
class Animal {
name: string
constructor(name: string = "动物") {
this.name = name
        }
run(distance: number = 0) {
console.log(`${this.name}跑了${distance}米`)
        }
    }
// 定义一个子类
class Dog extends Animal {
constructor(name: string) {
super(name)
        }
// 重写父类的实例方法
run(distance: number = 50) {
console.log(`${this.name}跑了${distance}米`)
        }
    }
// 定义一个子类
class Pig extends Animal {
constructor(name: string) {
super(name)
        }
run(distance: number = 20) {
console.log(`${this.name}跑了${distance}米`)
        }
    }
// 实例化父类对象
const ani: Animal = new Animal()
ani.run() //动物跑了0米
ani.run(150) //动物跑了150米
// 实例化子类对象
const dog1: Dog = new Dog("小黄")
dog1.run() //小黃跑了50米
const pig1: Pig = new Pig("佩奇")
pig1.run(30) //佩奇跑了30米

console.log("=====================")
// 多态:父类型的引用指向子类型的对象,不同类型的对象针对相同的方法,产生了不同的行为
const dog: Animal = new Dog("小黄")
dog.run() //小黃跑了50米
const pig: Animal = new Pig("佩奇")
pig.run() //佩奇跑了20米

console.log("=====================")
function showRun(ani: Animal) {
ani.run()
    }
showRun(dog) //小黃跑了50米
showRun(dog1) //小黃跑了50米
showRun(pig) //佩奇跑了20米
showRun(pig1) //佩奇跑了20米
})()
5、修饰符

【访问控制修饰符】TS中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。TS支持 3 种不同的访问权限。

修饰符

类内部

子类

类的外部

public,默认

可访问

可访问

可访问

protected

可访问

可访问

不能访问

private

可访问

不能访问

不能访问

【instanceof 运算符】instanceof 运算符用于判断对象是否是指定的类型,如果是返回 true,否则返回 false。

【readonly 修饰符】只读属性必须在声明时或构造函数里被初始化。

(1)readonly(只读)修饰成员属性

    readonly修饰后的成员属性:①不能在外部被随意的修改了。②构造函数,可以对只读属性成员数据进行修改。③如果构造函数中没有任何的参数,那么外部也不能对这个属性值进行更改。

(2)readonly修饰构造函数

构造函数中的参数(比如name参数),一旦使用readonly修饰后,①那么该参数name可以叫参数属性。②那么类就有了一个name的属性成员。③外部无法修改类中的name属性成员值。

// 一、readonly(只读)修饰成员属性,
// readonly修饰后的成员属性:
// 1、不能在外部被随意的修改了
// 2、构造函数,可以对只读属性成员数据进行修改
// 3、如果构造函数中没有任何的参数,那么外部也是不能对这个属性值进行更改的
(() => {
class Person {
readonly name: string
age: number
// 定义构造函数
constructor(name: string = "大大", age: number = 34) {
this.name = name
this.name = "梦"
this.age = age
        }
// 定义实例方法
sayHi() {
console.log(`我是${this.name}`)
        }
    }

const per = new Person("苗苗", 12)
// per.name = "菲菲" //报错:无法分配到 "name" ,因为它是只读属性。
console.log(per.name)
per.sayHi()

// 二、readonly修饰构造函数
// 构造函数中的name 参数,一旦使用readonly修饰后,
// 1、那么该name参数可以叫参数属性
///2、那么Animal类就有了一个name的属性成员
// 3、外部无法修改类中的name属性成员值

// 构造函数中的name 参数,一旦使用public/private/protected修饰后,
//那么Animal类就有了一个公共/私有/受保护的name属性成员了
class Animal {
constructor(public name: string = "大大") {
// this.name = name
        }
    }
const ani = new Animal("河马")
// ani.name = "猴子" //报错:无法分配到 "name" ,因为它是只读属性。
console.log(ani.name)
})()

【参数属性】在构造函数里,可以使用readonly,public,protected,private修饰其参数,例如 使用readonly name: string参数来创建和初始化 name 成员。 把声明和赋值合并至一处。

class Person {
  constructor(readonly name: string) {
  }
}

const p = new Person('jack')
console.log(p.name)
6、存取器 getters/setters

【存取器】TS支持通过 getters/setters来截取对对象成员的访问。 它能有效的控制对对象成员的访问。

// 存取器:
(() => {
class Person {
firstName: string
lastName: string
constructor(firstName: string, lastName: string) {
this.firstName = firstName
this.lastName = lastName
        }
// 读取器--负责读取数据
get fullName() {
return this.firstName + "_" + this.lastName
        }
// 设置器--负责数据的修改
set fullName(val) {
console.log("====set=====")
let names = val.split("_")
console.log("输出names", names)
this.firstName = names[0]
this.lastName = names[1]
        }
    }
const per = new Person("雷", "朗朗")
console.log(per, per.fullName)
per.fullName = "雷_哈哈"
console.log(per, per.fullName)
})()
7、静态属性

【静态属性】static,类对象的属性。

在类中通过static修饰的属性或方法,就是静态属性或静态方法,也称之为静态成员

 静态成员通过【类名.静态成员】方式进行调用。

构造函数不能通过static修饰。

(() => {
class Person {
static name1: string = "大哈哈"
name:String
constructor(name: string="小布丁") {
this.name= name
        }
sayHello(){
console.log("==sayHello===",this)
        }
static sayHi() {
//console.log("===sayHi===",this) //静态方法中不能使用this。this只能用于实例方法或构造方法中。
console.log(Person.name1)
        }
    }
Person.sayHi()
const per = new Person()
// console.log(Person.name1)
// console.log("=====");
Person.sayHi()
per.sayHello()
})()

【非静态属性】是类的实例对象的属性。

8、抽象类

【抽象类】抽象类做为其它派生类的基类使用,不能被实例化。不同于接口,抽象类可以包含未实现的抽象方法。 关键字abstract用于定义抽象类和在抽象类内部定义抽象方法。抽象类不能创建实例对象, 只有实现类才能创建实例。

(() => {
abstract class Animal {
abstract name: string = "动物"
//    抽象方法-没有具体的实现
abstract eat(): any
run() {
console.log("hello")
        }
    }
class Dog extends Animal {
name: string = "动物"
eat() {
console.log("舔着吃")
        }
    }
const dog = new Dog()
dog.eat()//舔着吃
})()

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐