【TypeScript】第四部分 面向对象
文章目录
4. 面向对象
4.1 什么是对象
- 举例来说:
- 操作浏览器要使用window对象
- 操作网页要使用document对象
- 操作控制台要使用console对象
一切操作都要通过对象,也就是所谓的面向对象,那么对象到底是什么呢?这就要先说到程序是什么,计算机程序的本质就是对现实事物的抽象,抽象的反义词是具体,比如:照片是对一个具体的人的抽象,汽车模型是对具体汽车的抽象等等。程序也是对事物的抽象,在程序中我们可以表示一个人、一条狗、一把枪、一颗子弹等等所有的事物。一个事物到了程序中就变成了一个对象。
在程序中所有的对象都被分成了两个部分数据和功能,以人为例,人的姓名、性别、年龄、身高、体重等属于数据,人可以说话、走路、吃饭、睡觉这些属于人的功能。数据在对象中被成为属性,而功能就被称为方法。所以简而言之,在程序中一切皆是对象。
4.2 类(class)
要想面向对象,操作对象,首先便要拥有对象,那么下一个问题就是如何创建对象。要创建对象,必须要先定义类,所谓的类可以理解为对象的模型,程序中可以根据类创建指定类型的对象
/*
用class关键字定义了一个Person类
对象主要包括两个部分:
属性
方法
*/
class Person{
/*
直接定义属性是实例属性,需要通过对象的实例去访问
*/
name = 'jack'
age = 18
/*
在属性的前使用static关键字可以去定义属性为静态属性(类属性)
该属性只能由类去访问
*/
static hello = '你好'
// 方法也是如此,直接写是由实例对象去访问,加了static关键字由类去访问
sayhello(){
console.log('大家好!!')
}
static sayhello1(){
console.log('我是静态方法')
}
}
// 实例化对象
const p = new Person();
console.log(p.name)
console.log(Person.hello)
p.sayhello()
Person.sayhello1()
4.3 构造函数和this
class Dog{
name:string
age:number
// constructor 被称为构造函数
// 构造函数会在对象创建时进行调用
// this指向当前创建的实例化对象
constructor(name:string,age:number){
this.name = name
this.age = age
}
bark(){
console.log('汪汪汪',this)
}
}
new Dog('旺财',2)
new Dog('小黑',2)
console.log(new Dog('旺财',2))
console.log(new Dog('小黑',2))
const d = new Dog('jack',4)
d.bark() // this指向jack
4.4 继承和重写
class Animal{
name:string
age:number
constructor(name:string,age:number){
this.name = name
this.age = age
}
sayhello(){
console.log('动物在叫~~~')
}
}
/*
extends 关键字用来继承父类
- 继承后子类将会拥有父类所有的方法和属性
- 继承用于:将多个类中共同的代码写在一个父类当中,这样可以
- 减少代码的重复性
- 在子类中可以添加自己独有的属性和方法
- 如果子类在添加了和父类相同的方法,则子类可以覆盖父类的方法
这种形式我们称为重写
*/
class Cat extends Animal{
run(){
console.log('咻咻咻')
}
sayhello(): void {
console.log('我是小猫')
}
}
class Mounse extends Animal{
eat(){
console.log('叽叽叽')
}
sayhello(): void {
console.log('我是老鼠')
}
}
const cat = new Cat('小七',2)
cat.sayhello()
cat.run()
const mouse = new Mounse('汤姆',5)
mouse.sayhello()
mouse.eat()
4.5 super关键字
class Animal1{
name:string
constructor(name:string){
this.name = name
}
sayhello(){
console.log('我是动物')
}
}
class Rabbit extends Animal1{
say(){
//在类方法中,super就相当于当前类的父类
super.sayhello()
}
}
const r = new Rabbit('小白')
r.say()
/*
当我们想要在子类上添加新的属性时候会发现问题
之前我们说过在子类上写相同的函数会被重写
这时候就需要使用super()去调用父类
*/
class Fish extends Animal1{
age:number
// 在子类写构造函数,就必须要调用父类的构造函数
constructor(name:string,age:number){
super(name) // 这个代码的意思是:调用父类的构造函数
this.age = age
}
sayhello(): void {
console.log('我是鱼')
}
}
const f = new Fish('喜喜',2)
f.sayhello()
4.6 抽象类
//抽象类和其他类的区别就是抽象类不能用来创建对象
//抽象类就是为了给其他类继承用的
abstract class Person1{
name:string
age:number
constructor(name:string,age:number){
this.name = name
this.age = age
}
// 定义抽象方法,没有具体的方法体
// 抽象方法只能被定义在抽象类中,子类继承后必须要重写该方法
abstract sayGoodBye():void
}
class Jack extends Person1{
gender:string
constructor(name:string,age:number,gender:string){
super(name,age)
this.gender = gender
}
sayGoodBye(): void {
console.log('bye bye')
}
}
const j = new Jack('丽华',12,'女')
j.sayGoodBye()
4.7 接口
接口的作用类似于抽象类,不同点在于接口中的所有方法和属性都是没有实值的,换句话说接口中的所有方法都是抽象方法(抽象类可以有其他方法和抽象方法)。接口主要负责定义一个类的结构,接口可以去限制一个对象的接口,对象只有包含接口中定义的所有属性和方法时才能匹配接口。同时,可以让一个类去实现接口,实现接口时类中要保护接口中的所有属性。
// 定义一个接口
interface botany{
name:string
flowerPhase:string
message():void
}
/*
定义类的时候可以使得类去实现一个接口
实现接口就是使类能够去满足接口的要求
*/
// 实现接口
class Rose implements botany{
name: string
flowerPhase: string
constructor(name:string,flowerPhase:string){
this.name = name
this.flowerPhase = flowerPhase
}
message(): void {
console.log(`我是${this.name},花期为${this.flowerPhase}`)
}
}
const rose = new Rose('玫瑰花','五个月')
rose.message()
4.8 属性的封装
TS可以在属性前添加修饰符
public
- 修饰的属性可以在任意位置访问/修改 默认值
private
- 私有属性 私有属性只能在该类内部进行访问/修改
因为设置了私有属性,所以只能由该类进行访问/修改
这时候我们可以通过定义方法将属性抛出,这样我们就可以
对属性做一些操作,比如:在修改年龄的时候加限制条件
- 私有属性 私有属性只能在该类内部进行访问/修改
protected
- 可以在该类和子类中进行访问/修改,实例对象无法进行访问/修改
class Person2{
private _name:string
private _age:number
protected _gender:string
constructor(name:string,age:number,gender:string){
this._name = name
this._age = age
this._gender = gender
}
/*
将getname和setname这种设置属性的方法称作为属性的存取器
*/
getage(){
return this._age
}
setage(value:number){
if(value >0)
{
this._age = value
}
}
/*
在TS中我们可以使用TS所提供的语法糖
语法:
get 方法名(){retun }
set 方法名(value:type){}
使用的时候就和平常访问修改一样
*/
get name(){
return this._name
}
set name(value:string){
this._name = value
}
}
class A extends Person2{
test(){
// 子类可以访问
console.log(this._gender)
}
}
const a = new A('mark',18,'female')
a.test() //
const p2 = new Person2('jack',12,'male')
console.log(p2.getage()) //12
p2.setage(33) //33
// 使用的时候就和平常一样
console.log(p2.name)
p2.name = 'mark'
console.log(p2)
4.9 泛型
定义一个函数或者是类的时候,有些情况是无法确定要使用的类型(返回值 、参数、属性的类型),这个时候就可以使用泛型.
/*
*/
function f1<T>(a:T):T{
return a
}
//当我们在调用时,如果不指定泛型TS会帮我们自动去推断类型
f1('hello') //此时泛型的值string
//当我们的代码很复杂时,TS不一定能够准确推断出类型
f1<number>(2222) //手动去指定泛型,能够更好的避免出错
// 可以指定多个泛型
class C<A,K>{
name:A
age:K
constructor(name:A,age:K){
this.name = name
this.age = age
}
}
const c = new C<string,number>('jack',18)
interface inter {
length:number
}
// 表示F必须是inter的实现类
function fn2 <F extends inter>(a:F):number{
return a.length
}
// 传进来的参数必须要有length这个属性
console.log(fn2('你好')) // 2
总结
以上就是今天要讲的内容,希望对大家有所帮助!!!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/82903.html