这是我参加「第四届青训营 」笔记创作活动的第八天。
1. 什么是面向对象
面向对象的编程语言是写程序所有的操作都是通过对象操作,所以叫面向对象。
2. 类
定义了对象是什么样子,相当于人的DNA,类可以理解为是对象的模型
3. 创建类
- 创建tsconfig.json文件并进行配置
{
"compilerOptions": {
"module": "ES2015",
"target": "ES2015",
"sourceMap": true,
"outDir": "./dist"
},
"include": ["./src/**/*"]
}
- 创建src文件夹并创建文件01-class.ts
//使用class关键字定义一个类
class Person {
//定义实例属性
name: string = "su";
//定义类属性/静态属性
static age: number = 18;
//readonly只读不改
readonly stu: string = "math";
//static和readonly可以一起用
//定义方法
sayHello() {
console.log("hi");
}
}
const per = new Person();
console.log(per);
console.log(per.name);
console.log(Person.age);
alert("a");
per.sayHello();
3.在part3创建index.html文件,并引入js,然后打开
目录结构
4. 构造函数
class Dog {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
break() {
console.log(this.name);
}
}
const dog = new Dog("xiaohei", 4);
console.log(dog);
dog.break()
5. 继承
super关键字
//立即执行函数避免变量发生冲突
(function () {
class Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
break() {
console.log("动物在叫");
}
}
class Dog extends Animal {
run() {
console.log("pao");
}
//子类添加父类相同方法,会覆盖
break() {
console.log("wang在叫");
}
}
class Cat extends Animal {
color:string;
//若添加新的属性必须先继承父类的,用super关键字
constructor(name: string, age: number,color:string){
super(name,age);
this.color=color
}
break() {
//引用父类
super.break();
}
}
const dog = new Dog("xiaohei", 4);
console.log(dog);
alert(dog.name);
dog.break();
dog.run();
const cat = new Cat("mao", 3,"black");
console.log(cat);
cat.break();
})();
6. 抽象类
//立即执行函数避免变量发生冲突
(function () {
//抽象类不能用来创建对象,就是拿来当父类使用。abstract
abstract class Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
//抽象类可以创建抽象方法
//抽象方法只能在抽象类中,子类必须对抽象方法进行重写
abstract break(): void;
}
class Dog extends Animal {
run() {
console.log("pao");
}
//子类添加父类相同方法,会覆盖
break() {
console.log("wang在叫");
}
}
const dog = new Dog("xiaohei", 4);
console.log(dog);
alert(dog.name);
dog.break();
dog.run();
})();
7. 接口:定义规范,对类进行限制
- 接口用来定义一个类结构,与上面的效果相同,定义一个类中应该包含哪些属性和方法,同时接口也可以当成类型声明取使用
- 接口可以重复声明,多个接口合并
- 接口可以在定义类的时候限制类的结构
- 类口中的所有属性不能有实际的值,而不考虑实际值
- 接口里面都是抽象方法
(function () {
//描述一个对象的类型
type User = {
name: string;
age: number;
};
const obj: User = {
name: "ss",
age: 19,
};
// 接口用来定义一个类结构,与上面的效果相同,定义一个类中应该包含哪些属性和方法,同时接口也可以当成类型声明取使用
//接口可以重复声明,多个接口合并
//接口可以在定义类的时候限制类的结构
//类口中的所有属性不能有实际的值,而不考虑实际值
interface myInterface {
name: string;
age: number;
}
interface myInterface {
gender: string;
sayHello(): void; //抽象方法
}
const obj1: myInterface = {
name: "ss",
age: 19,
gender: "female",
sayHello() {
console.log("hhh");
},
};
})();
定义类时,可以使类取实现一个接口。关键字:implements
//定义类时,可以使类取实现一个接口。关键字:implements,使类满足接口的要求
class Mycl implements myInterface {
name: string;
age: number;
gender: string;
constructor(name: string, age: number, gender: string) {
this.age = age;
this.name = name;
this.gender = gender;
}
sayHello() {
console.log("hahah");
}
}
})();
8. 封装:让属性更加安全
- public修饰的属性可以在任意位置访问(默认值)
- private修饰的属性只能在类内部进行访问
- 因为私有,所有外部拿不到,就需要定义一个方法可以获取内部属性
//立即执行函数避免变量发生冲突
(function () {
class Person {
name: string;
age: number;
//public修饰的属性可以在任意位置访问(默认值)
//private修饰的属性只能在类内部进行访问
public _sex: string;
private _course: string;
constructor(name: string, age: number, sex: string, course) {
this.name = name;
this.age = age;
this._sex = sex;
this._course = course;
}
//
//定义方法主动权在我们手上,比如可以设一个判断修改的值是否合法,让代码更健壮
//定义一个方法可以获取内部属性
getName() {
return this.name;
}
//定义一个方法可以修改内部属性
setName(value: string) {
//可以设一个判断修改的值是否合法
this._sex = value;
}
}
const per = new Person("xiaohei", 4, "female", "math");
console.log(per);
//数据可以任意修改,不安全
per.age = -3;
per._sex = "male";
// per._course = "chinese"; //会报错,属性“_course”为私有属性,只能在类“Person”中访问。
console.log(per);
console.log(per.getName());
per.setName("nan");
})();
TS中设置getter,setter方法的方式
//立即执行函数避免变量发生冲突
(function () {
class Person {
name: string;
age: number;
//public修饰的属性可以在任意位置访问(默认值)
//private修饰的属性只能在类内部进行访问
public _sex: string;
private _course: string;
constructor(name: string, age: number, sex: string, course) {
this.name = name;
this.age = age;
this._sex = sex;
this._course = course;
}
//TS中设置getter方法的方式
get course() {
return this._course;
}
//定义一个setter方法可以修改内部属性
set course(value: string) {
this._course = value;
}
}
const per = new Person("xiaohei", 4, "female", "math");
//使用习惯一样
console.log(per.course);
per.course = "ha";
console.log(per.course);
})();
protected受包含的属性,只能在当前类和当前类的子类中访问
(function () {
class A {
private num: number;
//protected受包含的属性,只能在当前类和当前类的子类中访问
protected age: number;
constructor(num: number, age: number) {
this.num = num;
this.age = age;
}
}
class B extends A {
test() {
// console.log(this.num); //属性“num”为私有属性,只能在类“A”中访问。
console.log(this.age);
}
}
})();
简便写法
//语法糖
(function () {
class C {
//可以直接将属性定义在构造函数中
constructor(public name: string, public age: number) {}
}
const c = new C("wh", 80);
//等价于
class C {
ame: string;
age: number
constructor(name: string, age: number) {
this.name=name;
this.age=age;
}
}
const c = new C("wh", 80);
})();
})();
泛型
在定义函数或者类时,遇到类型不明确就可以使用泛型
// function fn(a: number): number {
// return a;
// }
//在定义函数或者类时,遇到类型不明确就可以使用泛型
function fn<T>(a: T): T {
return a;
}
//可以直接调用具有泛型的函数
let s = fn(10); //不指定,TS自动对类型进行推断
let b = fn<string>("hello"); //指定泛型
//泛型可以同时指定多个
function fn2<T, K>(a: T, b: K): T {
return a;
}
fn2(12, "ok");
fn2<number, string>(12, "ok");
//T extends Inter表示泛型T必须是Inter实现类(子类)
interface Inter {
length: number;
}
function fn3<T extends Inter>(a: T): number {
return a.length;
}
fn3("123");
//类中使用
class Myclass<T> {
name: T;
constructor(name: T) {
this.name = name;
}
}
const mc = new Myclass<string>("wh");