面向对象
了解面向对象
面向对象程序设计(Object-oriented programming , OOP)是一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。
面向对象是程序中一个非常重要的思想。很多人都认为面向对象难,其实不难。简而言之就是程序之中所有的操作都需要通过对象来完成
举例子来说:
- 操作浏览器要使用window对象
- 操作网页要使用document对象
- 操作控制台要使用console对象
在程序中所有的对象都被分成两个部分数据和功能,以车为例,车的轮子,车身,车座位等属于数据,车可以开,按喇叭,加油等属于是车的功能,数据在对象中被称为属性,而功能就被成为方法,所以简而为之,在程序中一切皆是对象。
类
类就是对象的模型,使用class关键字来定义一个类
对象中主要包含两个部分:属性、方法
-
属性:
class Person{ /* * 直接定义的属性是实例属性,需要通过对象的实例去访问 * const per = new Person(); * per.name * 使用static开头的属性是静态属性(类属性),可以通过类去直接访问 * Person.age * 使用readonly开头的属性表示一个只读的属性无法修改 * */ // 实例属性 name: string = '帅哥'; // 静态属性 static age: number = 18; // 只读属性 readonly sex: string = '男'; } const per = new Person(); console.log(per.name) console.log(Person.age)
-
方法
class Person{ /* * 如果方法以static开头则方法就是类方法,可以直接通过类去调用 * */ static hello(){ console.log('hello') }; hi(){ console.log('hi') }; } per.hi() Person.hello()
构造函数
constructor被称为构造函数,构造函数会在对象创建时调用
class Dog{
name:string;
age:number;
constructor(name:string,age:number) {
// 在实例方法中,this就表示当前的实例
// 可以通过this向新建的对象添加属性
this.name = name
this.age = age
}
call(){
console.log(this)
}
}
const dog = new Dog('旺财',18)
const dog2 = new Dog('小白',2)
console.log(dog)
console.log(dog2)
dog.call()
继承
将一个类(a类)继承给另一个类(b类),那b类就会有a类的所有属性和方法。
下面我定义了两个类,这两个类中就sayHello这个方法不同而已,耦合度太高,就需要将它提取出来,减少耦合度就需要使用继承
// 定义一个宝马车的类
class Baoma {
length:number;
height:number;
constructor(length:number,height:number) {
this.length = length
this.height = height
}
sayHello(){
console.log('我是宝马')
}
}
// 定义一个奔驰车的类
class Benchi {
length: number;
height: number;
constructor(length: number, height: number) {
this.length = length
this.height = height
}
sayHello() {
console.log('我是奔驰')
}
}
定义一个Vehicle类为继承类也叫父类,并让Baoma类继承Vehicle类
// 定义一个继承类,车
class Vehicle{
length:number;
height:number;
constructor(length:number,height:number) {
this.length = length
this.height = height
}
sayHello(){
console.log('我是车')
}
}
/*
* Baoma extends Vehicle
* Vehicle为父类,Baoma为子类,使用了extends继承后
* 子类会拥有父类的所有属性和方法,通过继承可以将多个类中共有一套代码写在父类中
* 只需要写一次所有的子类就会拥有父类的所有属性和方法
* 如果希望在子类添加一些父类没有的属性和方法直接添加即可
* */
class Baoma extends Vehicle {
name:string = '宝马'
call(){
console.log(this.name)
}
}
const baoma = new Baoma(200,180)
baoma.sayHello()
baoma.call()
继承还有一个重要的方法叫重写,就是如果在子类中添加了和父类相同的方法,则子类方法就会覆盖父类的方法,从下面的例子就可以看到这两个子类sayHello方法输出的都是不一样的值
// 定义一个继承类,车
class Vehicle{
length:number;
height:number;
constructor(length:number,height:number) {
this.length = length
this.height = height
}
sayHello(){
console.log('我是车')
}
}
class Baoma extends Vehicle {
sayHello(){
console.log('我是宝马')
}
}
class Benchi extends Vehicle {
sayHello(){
console.log('我是奔驰')
}
}
const baoma = new Baoma(200,180)
const benchi = new Benchi(500,400)
baoma.sayHello()
benchi.sayHello()
super关键字
在类的方法中,super就表示当前类的父类。
如果在子类中写了构造函数,在子类的构造函数中必须对父类的构造函数进行调用。
class Vehicle{
name:string;
constructor(name:string) {
this.name = name
}
sayHello(){
console.log('车车车')
}
}
class Baoma extends Vehicle{
age:number
constructor(name:string, age:number) {
// 如果在子类中写了构造函数,在子类的构造函数中必须对父类的构造函数进行调用
super(name); // 调用父类构造函数
this.age = age
}
sayHello(){
// 在类的方法中,super就表示当前类的父类
super.sayHello()
console.log('宝马')
}
}
const baoma = new Baoma('宝马',18)
baoma.sayHello()
抽象类abstract
以abstract开头的类是抽象类。
抽象类和其他类区别不大,只是不能用来创建对象,抽象类就是专门用来被继承的类。
abstract class Vehicle{
name:string;
constructor(name:string) {
this.name = name
}
// 定义一个抽象方法,抽象方法使用abstract开头,没有方法体
// 抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写
abstract sayHello():void;
}
class Baoma extends Vehicle{
sayHello(){
console.log('宝马')
}
}
const baoma = new Baoma('宝马')
baoma.sayHello()
项目interface
接口用来定义一个类结构,包含属性和方法,同时接口也可以当成类型声明去使用
/*
* 接口中的所有属性都不能有实际的值
* 接口只定义对象的结构,而不考虑实际值
* 在接口中所有的方法都是抽象方法
* 接口是可以使用重复的名字,重复名字的接口是会拼在一起的
* */
interface myInterface {
name : string,
age : number,
sayHello():void
}
interface myInterface {
sayHello():void
}
class MyClass implements myInterface{
name:string;
age:number;
constructor(name:string,age:number) {
this.name = name
this.age = age
}
sayHello(){
console.log(this.name)
}
}
typescript类属性修饰符
pubilc 修饰的属性可以在任意位置访问(修改)pubilc为默认值
private 私有属性,私有属性只能在类内部进行访问(修改)
protected 受包含的属性,只能在当前类和当前类的子类中访问(修改)
class People {
public name:string
private age:number
protected sex:string
constructor(name:string,age:number,sex:string) {
this.name = name
this.age = age
this.sex = sex
}
}
const people = new People('帅哥',18,'男')
// age和sex是不能修改的
people.name = '美女'
class Female extends People{
// age是不能修改的,name和sex都是可以修改的
setsex(){
this.sex = '女'
console.log(this.sex)
}
}
const female = new Female('美女',19,'男')
female.setsex()
泛型
- 在什么情况下用泛型
在定义函数或者是类时,如果遇到类型不明确就可以使用泛型 - 可以直接调用具有泛型的函数
function fn<T>(a:T):T{
return a
}
// 不指定泛型,TS可以自动对类型进行推断
let a = fn(10)
// 指定泛型
let b = fn<string>('hello')
console.log(a)
console.log(b)
泛型可以同时指定多个
function fn2<T,K>(a:T, b:K):T{
console.log(b)
return a
}
fn2<number,string>(123,'hello')