对象,类与属性
- 一.类(class)
- 1.属性与方法
- 2.构造器
- 3.继承
- 4.super关键字
- 二.抽象类与抽象方法
- 三.接口
- 四.属性的封装
- 五.泛型
- 笔记说明
一.类(class)
- 类可以理解为对象的模型,通过类来创建对象
1.属性与方法
- 一个类主要包含两个部分,属性与方法
// 使用class关键字定义一个类
/**
* 类主要包含两部分:
* 1.属性
* 2.方法
*/
class Person {
// 静态属性,从属于类 可以直接通过类来访问
static id: number = 9527;
// 示例属性,从属于对象 需要通过类的实例对象去访问
name: string = "iFinder";
age: number = 24;
// 只读属性, readonly开头,不能更改只能读取
readonly country:string = "china";
// 方法
// 同理如果方法用static修饰,该方法便可以通过类去调用
sayGood() {
console.log("Good !");
}
}
const per = new Person();
per.sayGood();
console.log(per.name);
console.log(per.age);
// 静态属性
console.log(Person.id);
2.构造器
- 创建多个对象的时候,我们希望在创建对象时就赋予它不同的属性,这时就可以通过构造器来实现这样的需求
class Dog {
name: string
age: number
/**
* 构造器,在创建多个对象的时候,创建对象时调用的函数
*/
constructor(name: string, age: number) {
// this表示的就是当前的示例,可以通过他向新建的对象中添加属性
this.name = name
this.age = age
}
bark() {
alert('汪 !')
}
}
class Cat {
// ts也可以将属性快速的定义在构造器当中, 简化了属性的写法
constructor(public name:string, public age:number) {
}
}
const dog1 = new Dog('dog1', 4)
const dog2 = new Dog('dog2', 5)
const dog3 = new Dog('dog3', 6)
console.log(dog1)
console.log(dog2)
console.log(dog3)
3.继承
- 可以通过继承,将多个类共有的属性与方法抽象出来,作为公共的父类.这样可以大大提高代码的利用率
- 子类直接继承父类,可以直接拥有父类的属性与方法
(function(){
// 创建一个表示动物的类
// 通过继承,可以把多个类共有得属性与方法抽象成公共得父类,这样就提高了代码得复用性
class Animal {
name: string
age: number
constructor(name: string, age: number){
this.name = name
this.age = age
}
sayHello() {
console.log(`${this.name} 在 叫 !`)
}
}
// 让Dog类继承自动物类
// 这时Animal就是Dog的父类,子类将会拥有父类所有的方法与属性
class Dog extends Animal {
// 可以实现自己独有得方法
run() {
console.log(`${this.name} 在 跑!`)
}
// 可以重写父类的方法实现自己特有的功能
// 子类的方法会覆盖父类的方法
sayHello() {
console.log(`${this.name} 在 汪汪汪 !`)
}
}
class Cat extends Animal {
sayHello() {
console.log(`${this.name} 在 喵喵喵 !`)
}
}
const dog = new Dog('小黑狗', 4)
const cat = new Cat('小花猫', 6)
dog.sayHello()
cat.sayHello()
})()
4.super关键字
- 子类继承父类之后,如果想调用父类中的属性或者方法,可以通过super关键字
- 子类如果重新实现了构造器,那么需要在自己的构造器中通过super调用父类的构造器
(()=>{
class Animal {
name: string
constructor(name:string) {
this.name = name
}
sayHello() {
console.log("动物叫")
}
}
class Dog extends Animal {
age: number
// 如果在子类中重新实现了构造器,那么需要通过super调用父类的构造器
constructor(name:string, age:number) {
super(name)
// 子类新添加的属性需要自己实现
this.age = age
}
sayHello() {
// 在类的方法中,super表示当前类的父类
// 这里可以理解为直接调用了父类的sayHello方法
super.sayHello()
}
}
const dog = new Dog('小黑', 8)
dog.sayHello()
})()
二.抽象类与抽象方法
- 当你定义了一个公共父类,并且只想被继承,不想拥有具体实例的时候就可以通过abstract修饰,使之成为抽象类
- 抽象类中你想定义子类必须实现的某些方法,可以定义抽象方法
(()=>{
/**
* 以abstract开头的类是抽象类
* 只能被继承,不能直接实例化
*
* 抽象类中可以添加抽象方法(规定一个必须实现的方法,让不同的类去实现)
*/
abstract class Animal {
name: string
constructor(name:string) {
this.name = name
}
// 不定义具体的实现,由子类去实现具体的方法体
// 抽象方法只能被定义在抽象类中
abstract sayHello(): void
}
class Dog extends Animal {
// 抽象方法会强制子类去添加具体的实现
sayHello(): void {
console.log(`${this.name} 在 汪汪汪 !`)
}
}
const dog = new Dog('小黑')
dog.sayHello()
})()
三.接口
(()=>{
// type关键字描述对象的类型
type myType = {
name: string,
age: number
}
/**
* 接口用来定义一个类的结构
* 可以定义一个类型中应该包含哪些方法
*/
interface myInterFace {
name: string
age: number
}
// 接口可以重复声明,但是在作为类型使用的时候属性是叠加的
interface myInterFace {
gender: string
}
/**
* 接口可以在定义类的时候限制类的结构
* 接口中的所有属性都不能有实际的值
* 接口值定义对象的结构,不考虑实际的值
*/
interface inter{
name: string
sayHello(): void
}
// 定义类的时候可以让这个类实现这个接口
class MyClass implements inter {
name: string = "iFinder"
sayHello(): void {
//...
}
}
})()
四.属性的封装
- TS的类中的属性,如果不加以修饰的话就是任何人都能访问与修改的,这样就造成的属性数据的不安全
- 通过封装,可以将属性一定程度上的保护起来
- 封装后只提供给调用方相应的方法,这样设置与获取数据的方法就是开发者可控的,提高了数据的安全性
(()=>{
// 定义一个人类
class Person {
/**
* 有的时候我们不希望对象中的属性被随意的修改,这时就需要将属性封装起来
* 这时候可以通过属性修饰符来对属性进行封装
*
* public: (默认)修饰的属性可以再任意位置被访问
* private: 私有属性,只能在类的内部进行访问与修改
* --这时通过在类中添加方法,让外部通过这个方法访问这个属性
* --这时修改与访问的方法都是开发者提供的,这样这个属性的访问就变得可控了
* protected: 当前类和子类能都访问与修改,外部不能访问与修改
*/
private _name:string
private _age:number
constructor(name:string, age:number) {
this._name = name
this._age = age
}
// 给外部的类提供一个访问私有属性的方法
getName():string {
return this._name;
}
// set的时候限制name的类型
setName(name:string) {
this._name = name;
}
// set的时候限制年龄不会为负值
setAge(age:number) {
if(age >= 1) {
this._age = age;
}
}
// TS中独有的getter和setter方法
get age():number {
return this._age >= 1 ? this._age : 1;
}
set age(age:number) {
if(age >= 1) {
this._age = age;
}
}
}
// TS独有的写法可以直接用类似属性的方法来进行设置
const p = new Person("iFinder", 25);
console.log(p.age); // 这时会调用get age方法获取属性
p.age = -1; // 这时会调用set age方法设置属性
console.log(p.age); // 方法中有判断,此时的打印依旧是25
})()
五.泛型
- 定义函数或者声明一个类的时候如果暂时不能确定具体的类型,但是又想保持某种类型的统一,不想通过any破环TS的类型检查机制,就可以通过指定泛型的方式来达到这个要求
(()=>{
/**
* 定义函数或者类的时候,如果遇到类型不明确的,可以使用泛型
* <V>定义了一个叫V的泛型
*/
function fn<V>(a: V): V {
return a;
}
// 直接调用具有泛型的函数,这时泛型的类型就是number
let a:number = fn(10)
// 可以直接指定泛型的类型
let s:string = fn<string>('iFinder')
//可以指定多个泛型
function fn1<K, T>(a: T, b: K): T {
return a;
}
// 定义的时候就指定泛型的类型
interface Inter{
length:number
getLength(): number
}
abstract class Animal {
info:string;
constructor(private _name:string, private _age:number) {
this.info = `name: ${_name}, age: ${_age}`
}
get name(){
return this._name
}
set age(age:number) {
this._age = age
}
}
function fn2<T extends Inter, K extends Animal>(a: T, b: K): K {
return b
}
// 通过泛型指定类中的某种类型
class MyClass<T>{
constructor(public name:T) {}
}
// 创建类的时候确定泛型类型
let my = new MyClass<string>("iFinder")
})()
笔记说明
笔记markdown文件+项目源码
B站对应视频