定义
类是面向对象编程的基石,因为vue和react的缘故,工作很少用,一般大量用于框架,ts也对类做了很好的支持
class Person{
name:string;//只定义类型
name='Tom';//直接赋值
constructor(name:string){
this.name=name;
}
}
可以在属性声明的时候直接赋值,也可以在构造函数中赋值,以构造函数里边的赋值为最后赋值
class Person{
name:string;//只定义类型
constructor(name='Tom'){
this.name=name;
}
}
也可以在构造函数中定义默认值
class Person{
name:string;//只定义类型
constructor(name='Tom'){
this.name=name;
}
sayHello(){
console.log(`hello!${this.name}`)
}
}
定义函数方法也是一样的
只读readonly
class Person{
readonly name:string;//只定义类型
constructor(name='Tom'){
this.name=name;
}
}
const person=new Person()
person.name='Jack'//报错因为它是只读属性
只读属性只能在定义或者构造函数中赋值
函数的重载
class Person{
readonly name:string='Tom';//只定义类型
readonly age:number=18;
readonly sex:number=1;
constructor(name:string,sex?:number)
constructor(age:number)
constructor(nameOrAge:string|number,sex?:number){
if(typeof nameOrAge === "string"){
this.name=nameOrAge;
this.sex=sex as number;
}else{
this.age=nameOrAge;
}
}
}
const p1=new Person("Jerry",1);
console.log(p1.name);
const p2=new Person(20);
console.log(p2.age);
构造函数的重载格式就是上边这样,可以传入一个参数也可以传入多个,这里有个问题是必须给属性一个默认值 否则就报错,另外第二个参数要写成可选参数,并且赋值的时候要使用as,因为sex定义的是number,传入的时候因为是可选属性所以它的类型是number|undefined,直接赋值会报错的
class Person{
readonly name:string='Tom';//只定义类型
constructor(name:string):string{//报错
this.name=name;
}
}
不能给构造函数手动设置返回值,因为它总是返回实例也就是this
类的get和set
class Circle {
#radius; // 私有属性
constructor(radius: number) {
this.#radius = radius; // 使用下划线来表示私有属性
}
get radius() {
return this.#radius; // 定义获取半径的行为
}
set radius(newRadius) {
if (newRadius <= 0) {
throw new Error("半径必须大于0");
}
this.#radius = newRadius; // 定义设置半径的行为
}
get area() {
return Math.PI * this.#radius ** 2; // 定义获取面积的行为
}
}
const c = new Circle(5);
console.log(c.radius); // 输出: 5
console.log(c.area); // 输出: 78.54
c.radius = 3;
console.log(c.radius); // 输出: 3
console.log(c.area); // 输出: 28.27
c.radius = -1; // 报错: Uncaught Error: 半径必须大于0
是不是有pinia和计算属性的感觉,其实用函数也能实现这些功能,但是用get和set更加符合面向对象的思想,维护性也更高,说白了就是逼格更高
属性索引
class Person{
[property:string]:string|((s:0|1)=>boolean);
#name='张三'
isBoy(sex:0|1){
console.log('boy name is:',this.#name);
return Boolean(sex);
}
sayName(){//报错 类型“() => string”的属性“sayName”不能赋给“string”索引类型“string | ((s: 0 | 1) => boolean)”
return 'boy name is:'+this.#name
}
}
这样定义代表这个类只包含类型为string的属性或返回值为布尔的方法,不能包含其它的。
implements 的使用
interface Person{
name: string;
age: number;
}
type Person={
name: string;
age: number;
}
class PersonClass implements Person{
name="John";
age=30;
}
type或interface定义都可以,然后类名称后用implements,另外需要注意的是implements并不是像type和interface那样,他只是检测下这个类是不是满足你定义的类型,下边这个例子解释下我想说的
interface Person{
name: string;
age?: number;
}
const person1: Person={name:'Tome'};
person1.age=19;
class PersonClass implements Person{
name="John";
}
const person = new PersonClass();
person.age = 25;//报错 提示实例上没有age属性
可以对比下差别。
implements后边还可以加另一个类
class Car{
name='BMW';
}
class PersonClass implements Car{
name="John";//不能省略
}
类与接口的合并
class Car{
name='BMW';
}
interface Car{
color:string;
}
let myCar=new Car();
myCar.color='red';
当类和接口同名时,会产生合并,这也算ts的一大特性吧。但是别名 type不行 会报错的
未完待续...
因类后边要注意的东西过于复杂且应用场景较少,后边的教程以后再更新吧