在 Vue 3 的 <script setup> + Composition API 风格中,
几乎不用 class,而是用 interfacetyperefreactive 等函数式/组合式写法。
但在某些场景下,class 依然有用。

Vue 3 的主流写法是 <script setup> + setup() + ref/reactive
class在vue3/uniapp中,在以下场景还是会用到class:

场景1:定义复杂数据模型(Domain Model)

比如你有一个"用户"类,带方法:

ts 复制代码
// model/User.ts
export class User {
  id: number;
  name: string;
  email?: string;

  constructor(id: number, name: string, email?: string) {
    this.id = id;
    this.name = name;
    this.email = email;
  }

  // 方法:获取用户简介
  getIntro(): string {
    return `${this.name} (${this.email || "无邮箱"})`;
  }

  // 方法:是否是管理员
  isAdmin(): boolean {
    return this.id === 1;
  }
}

然后在组件中使用:

ts 复制代码
const user = new User(101, '李四', 'lisi@example.com') 
console.log(user.getIntro()) // 李四 (lisi@example.com)

用途:封装业务逻辑,比纯对象更强大。

场景2:封装工具类(Utils Class)

ts 复制代码
// utils/Storage.ts
export class Storage {
  static set(key: string, value: any) {
    uni.setStorageSync(key, JSON.stringify(value))
  }

  static get(key: string): any {
    const data = uni.getStorageSync(key)
    return data ? JSON.parse(data) : null
  }

  static remove(key: string) {
    uni.removeStorageSync(key)
  }
}

// 使用
Storage.set('token', 'abc123')
const token = Storage.get('token')

用途:封装本地存储、网络请求、加密等通用功能。

场景3:状态管理中使用class(配合Pinia或自定义Store)

虽然Pinia推荐用defineStore,但你也可以用class管理复杂状态:

ts 复制代码
// utils/Storage.ts
export class Storage {
  static set(key: string, value: any) {
    uni.setStorageSync(key, JSON.stringify(value))
  }

  static get(key: string): any {
    const data = uni.getStorageSync(key)
    return data ? JSON.parse(data) : null
  }

  static remove(key: string) {
    uni.removeStorageSync(key)
  }
}

// 使用
Storage.set('token', 'abc123')
const token = Storage.get('token')

然后在组件中:

ts 复制代码
import {userStore} from '@/store/UserStore'

userStore.login('admin','123')

场景4:封装网络请求(API Client)

ts 复制代码
// api/ApiClient.ts
export class ApiClient {
  private baseUrl: string
  private token?: string

  constructor(baseUrl: string) {
    this.baseUrl = baseUrl
  }

  setToken(token: string) {
    this.token = token
  }

  async request<T>(url: string, method: string, data?: any) {
    const res = await uni.request({
      url: this.baseUrl + url,
      method,
      data,
      header: {
        Authorization: this.token ? `Bearer ${this.token}` : ''
      }
    })
    return res.data as T
  }

  get<T>(url: string) {
    return this.request<T>(url, 'GET')
  }

  post<T>(url: string, data: any) {
    return this.request<T>(url, 'POST', data)
  }
}

// 使用
const api = new ApiClient('https://api.example.com')
const posts = await api.get<PostListResponse>('/posts')
</script>

这比每次写uni.request更优雅、可复用。

class在Vue3.0/Uniapp中的定位
  1. 封装业务逻辑(如User) class+方法很适合
  2. 工具类(Storage/Utils)静态方法方便调用
  3. API请求客户端(封装baseUrl、token、错误处理)
  4. 状态管理(复杂逻辑) 比纯对象更易维护

组件用setup,模型用class,数据用interface,工具用static。

UserManager class 案例:

用户登录/登出 本地存储(持久化) 自动刷新Token(模拟) 权限判断 登录状态监听 TypeScript类+静态单例模式

场景:用户管理系统:用户登录后保存信息和 token,能判断是否登录、是否是管理员、自动续期 token。

src/utils/UserManager.ts

1.定义User接口(数据结构)

ts 复制代码
// types/User.ts 或直接写在 UserManager.ts 顶部 
export interface User {
    id: number; 
    name: string; 
    email: string;
    avatar?: string; 
    role: 'user' | 'admin'; // 角色
}

2.编写UserManager类(核心)

ts 复制代码
// utils/UserManager.ts

import type { User } from '@/types/User'; // 引入类型

// 模拟 API 延迟
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

export class UserManager {
  private user: User | null = null;
  private token: string | null = null;
  private refreshToken: string | null = null;
  private expiresAt: number = 0; // token 过期时间戳

  // 监听器列表(用于通知组件状态变化)
  private listeners: Array<(user: User | null) => void> = [];

  // 私有构造函数(单例模式)
  private constructor() {
    // 初始化时从本地恢复登录状态
    this.restoreSession();
  }

  // 静态实例(全局唯一)
  private static instance: UserManager;

  // 获取单例实例
  public static getInstance(): UserManager {
    if (!UserManager.instance) {
      UserManager.instance = new UserManager();
    }
    return UserManager.instance;
  }

  // ============ 核心方法 ============

  /**
   * 登录
   */
  async login(username: string, password: string): Promise<{ success: true } | { success: false; message: string }> {
    await sleep(800); // 模拟网络延迟

    // 简单模拟验证(实际应调用 API)
    if (username === 'admin' && password === '123') {
      const user: User = {
        id: 1,
        name: '管理员',
        email: 'admin@example.com',
        avatar: 'https://i.pravatar.cc/150?u=admin',
        role: 'admin'
      };
      this.setSession(user, 'fake-jwt-token', 'fake-refresh-token', 30 * 60); // 30分钟过期
      return { success: true };
    } else if (username === 'user' && password === '123') {
      const user: User = {
        id: 2,
        name: '普通用户',
        email: 'user@example.com',
        avatar: 'https://i.pravatar.cc/150?u=user',
        role: 'user'
      };
      this.setSession(user, 'fake-user-token', 'fake-user-refresh', 30 * 60);
      return { success: true };
    } else {
      return { success: false, message: '用户名或密码错误' };
    }
  }

  /**
   * 登出
   */
  logout() {
    this.user = null;
    this.token = null;
    this.refreshToken = null;
    this.expiresAt = 0;
    uni.removeStorageSync('user_session');
    this.notifyListeners(null);
  }

  /**
   * 刷新 Token(模拟)
   */
  async refreshTokenIfNeeded(): Promise<boolean> {
    if (this.token && this.expiresAt < Date.now()) {
      await sleep(500);
      // 模拟刷新
      this.token = this.token + '-refreshed';
      this.expiresAt = Date.now() + 30 * 60 * 1000;
      this.saveSession();
      return true;
    }
    return false;
  }

  // ============ 工具方法 ============

  /**
   * 设置会话
   */
  private setSession(user: User, token: string, refreshToken: string, expiresIn: number) {
    this.user = user;
    this.token = token;
    this.refreshToken = refreshToken;
    this.expiresAt = Date.now() + expiresIn * 1000;
    this.saveSession();
    this.notifyListeners(user);
  }

  /**
   * 保存会话到本地
   */
  private saveSession() {
    const session = {
      user: this.user,
      token: this.token,
      refreshToken: this.refreshToken,
      expiresAt: this.expiresAt
    };
    uni.setStorageSync('user_session', JSON.stringify(session));
  }

  /**
   * 从本地恢复会话
   */
  private restoreSession() {
    try {
      const sessionStr = uni.getStorageSync('user_session');
      if (!sessionStr) return;

      const session = JSON.parse(sessionStr);
      if (session.expiresAt > Date.now()) {
        this.user = session.user;
        this.token = session.token;
        this.refreshToken = session.refreshToken;
        this.expiresAt = session.expiresAt;
      } else {
        // 过期了就清空
        uni.removeStorageSync('user_session');
      }
    } catch (e) {
      console.error('恢复会话失败', e);
    }
  }

  /**
   * 通知所有监听器
   */
  private notifyListeners(user: User | null) {
    this.listeners.forEach(fn => fn(user));
  }

  // ============ 获取状态的方法 ============

  /**
   * 获取当前用户
   */
  getUser(): User | null {
    return this.user;
  }

  /**
   * 获取 Token
   */
  getToken(): string | null {
    return this.token;
  }

  /**
   * 是否已登录
   */
  isLoggedIn(): boolean {
    return !!this.user && this.expiresAt > Date.now();
  }

  /**
   * 是否是管理员
   */
  isAdmin(): boolean {
    return this.user?.role === 'admin';
  }

  /**
   * 添加状态监听器(比如组件想监听登录状态变化)
   */
  onStatusChange(callback: (user: User | null) => void) {
    this.listeners.push(callback);
    // 立即触发一次当前状态
    callback(this.user);
    // 返回取消订阅函数
    return () => {
      this.listeners = this.listeners.filter(fn => fn !== callback);
    };
  }
}

在组件中使用

index.vue 复制代码
<template>
  <div>
    <h2>用户管理系统</h2>

    <div v-if="!userManager.isLoggedIn()">
      <p>当前未登录</p>
      <button @click="handleLogin" :disabled="loading">
        {{ loading ? "登录中..." : "以管理员登录" }}
      </button>
    </div>

    <div v-else>
      <p>你好,{{ currentUser?.name }}!</p>
      <p>角色:{{ currentUser?.role }}</p>
      <p>邮箱:{{ currentUser?.email }}</p>
      <button @click="handleLogout">登出</button>
    </div>
  </div>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { UserManager } from "@/utils/UserManager";

// 获取单例
const userManager = UserManager.getInstance();

// 响应式数据
const currentUser = ref<User | null>(null);
const loading = ref(false);

// 登录方法
const handleLogin = async () => {
  loading.value = true;
  const result = await userManager.login("admin", "123");
  if (result.success) {
    console.log("登录成功");
  } else {
    console.error(result.message);
  }
  loading.value = false;
};

// 登出
const handleLogout = () => {
  userManager.logout();
};

// 监听登录状态变化
onMounted(() => {
  // 添加监听器
  const unsubscribe = userManager.onStatusChange((user) => {
    currentUser.value = user;
  });

  // 组件销毁时取消监听(可选,一般不需要)
  // onUnmounted(unsubscribe);
});
</script>

正题:当你看完上述的这几个案例,现在我们来看类的使用例子:

ts 复制代码
// class就是定义类的关键字
//Greeter这个是类的名称,一般就是大驼峰命名如:PascalCase。
//greeting: string; 
// greeting是类的实例属性,或称为成员变量。每个通过new Greetter(...)创建的对象都会拥有属于自己独立的greeting属性。
// : string 这是ts的类型注解,明确了greeting属性的类型必须是string,ts的核心之一,检查属性,提供了安全性。
//constructor这是类的构造函数。
//message: string 这是构造函数的参数。它会接收一个string类型的 参数message,
// 当你调用new Greeter("world")时,"world"这个字符就会作为message参数传递给构造函数。
class Greeter {
    greeting: string; // 属性声明 (修正了拼写: gerrting -> greeting)
    constructor(message: string) { // 构造函数
        this.greeting = message; // 赋值!this.greeting = message;作用是将传入的message参数的值赋给当前实例的greeting属性。这是初始化实例属性的关键步骤。
    }

    greet() { // 方法或者称为成员函数。它定义了Greeter类的实例可以执行的操作。
        return "Hello, " + this.greeting; // 这个方法的逻辑:返回一个字符串,该字符串由"hello"和当前实例的greeting属性值拼接而成。
										  // this.greeting;确保了它访问的是调用该方法的那个特定实例的greeting值。
    }
}

let greeter = new Greeter("world"); // 创建实例(这就是实例化的过程。)
// new关键字告诉js/ts引擎要创建一个Greeter类的新对象(实例)。
//  Greeter("world")表示调用Greeter类的构造函数,并将"world"作为参数传递。
// 构造函数执行this.greeter=message;将新创建的实例的greeting属性设置为"world"
// let greeter = ...: 这行代码将新创建的 Greeter 实例赋值给一个名为 greeter 的变量。现在,greeter 就是一个具体的 Greeter 对象。
类的继承

类从基类中继承了属性和方法。这里,Dog是一个派生类,它派生自Animal基类,通过extends关键字。派生类通常被称作子类,基类通常被称作超类。

ts 复制代码
// class就是定义类的关键字
// Animal就是类的名称
// move是Animal类中的方法
// distanceInMeters: number方法中的参数
// = 0是默认参数值,如果调用move这个方法时没有提供参数,distanceInMeters的值将自动设为0.

class Animal {
    move(distanceInMeters: number = 0) {
        console.log(`Animal moved ${distanceInMeters}m.`);
    }
}

//extends这是继承的关系  Dog继承了Animal类。
// Dog类自动获得了Animal类中定义的所有公告属性和方法(在这个例子中就是move方法)。
// Dog类被称为Animal类的子类(或派生类)。
// Dog可以在继承的基础上添加自己特有的属性和方法。
// bark() { ... }这是Dog类自己定义的一个特有方法。它代表了狗这种动物特有的行为:叫(bark)
// 调用了bark()会打印出来'Woof! Woof!'。
// 重要的是Animal类的实例不能调用bark()方法,因为bark是Dog类特有的。
class Dog extends Animal {
    bark() {
        console.log('Woof! Woof!');
    }
}

// const dog = new Dog();使用new关键字创建Dog类的一个新实例(对象),并将其赋值给常量dog.
// 这个dog实例:
// 拥有从Animal继承来的move方法,拥有Dog类自己定义的bark方法。
const dog = new Dog();
dog.bark();
dog.move(10);
dog.bark();

// Woof! Woof!
// Animal moved 10m.
// Woof! Woof!
ts 复制代码
class Animal {
    name: string;
    constructor(theName: string) { this.name = theName; }
    move(distanceInMeters: number = 0) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}

class Snake extends Animal { //继承 Animal
    constructor(name: string) { super(name); } //构造函数
    move(distanceInMeters = 5) { //方法重写
        console.log("Slithering...");
        super.move(distanceInMeters);
    }
}

class Horse extends Animal { //继承 Animal
    constructor(name: string) { super(name); } //构造函数
    move(distanceInMeters = 45) {  //方法重写
        console.log("Galloping...");
        super.move(distanceInMeters);
    }
}

let sam = new Snake("Sammy the Python");  //创建一个snake的实例
let tom: Animal = new Horse("Tommy the Palomino");  //创建一个Horse的实例

sam.move();
tom.move(34);

// Sammy the Python moved 5m.
// Tommy the Palomino moved 34m.

公共,私有与受保护的修饰符。

默认为public

ts里,成员都默认为public。 c#要求必须明确地使用public指定成员是可见的。

ts 复制代码
//class 类的关键词
//Animal类的名称
//public这是访问修饰符。public表示这个成员(属性或方法)是公开的,可以从类的内部和外部(通过实例)自由访问。
//public name: string;公开的名称信息和名称属性。
//public constructor(theName: string) { this.name = theName; }公平的构造函数,constructor这是类的构造函数,当使用 new Animal(...) 创建类的新实例时,构造函数会自动执行。
//this.name = theName;构造函数的方法体(代码体)。
 // public move(distanceInMeters: number) 表示公开的move
class Animal {
    public name: string;
    public constructor(theName: string) { this.name = theName; }
    public move(distanceInMeters: number) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}

// 1. 创建实例 (使用 new 关键字和构造函数)
let lion = new Animal("Lion"); // 构造函数被调用,theName = "Lion", lion.name 被设为 "Lion"

// 2. 访问公开属性 (因为 name 是 public)
console.log(lion.name); // 输出: Lion

// 3. 调用公开方法 (因为 move 是 public)
lion.move(15); // 输出: Lion moved 15m.

// 4. 修改公开属性 (因为 name 是 public)
lion.name = "Tiger";
lion.move(5);  // 输出: Tiger moved 5m.

理解private 私有的

当成员被标记成private时,它就不能在申明它的类的外部访问。

ts 复制代码
//private成员是"私有的":他们就行是类的"内部秘密"或"内部工作细节"。
//只能在"类"的内部使用:你只能在定义这个private成员的那个类的内部代码
//(比如其他方法或构造函数)中访问它。
//不能在类的"外部"使用:一旦你创建了这个类的实力(对象),
//帮你就不能通过这个实例在类的外部直接读取或修改private的属性,也不能直接调用private的方法。
class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}

new Animal("Cat").name; // 错误: 'name' 是私有的.
ts 复制代码
//定义了一个Animal类,包含了一个私有属性name
class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}
//Rhino类继承了Animal,所以它拥有Animal的结构,包括那个private name属性。
class Rhino extends Animal {
    constructor() { super("Rhino"); }
}

// Employee类也有一个同名的私有属性name,看起来和Animal很相似。
class Employee {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}

// 变量声明与复制
let animal = new Animal("Goat");
let rhino = new Rhino();
let employee = new Employee("Bob");

animal = rhino;

// ts使用结构化类型系统,意思就是两个类型如果有相同的结构,就可以互相赋值。
// 但有一个重要的例外,当类包含private成员时,他们只会在来自同一个基类(或声明位置相同)时才被认为是兼容的。
// "Animal 的 private name" 和 "Employee 的 private name" 是不同来源的私有成员,因此 Animal 和 Employee 结构不兼容。
animal = employee; // 错误: Animal 与 Employee 不兼容.

理解protected 受保护的

protected成员在派生类中仍然可以访问。

ts 复制代码
// protected 的含义是成员可以在类内部以及其子类中访问,但不能在类的实例外部访问。
class Person {
    protected name: string;
    constructor(name: string) { this.name = name; }
}

//Employee 继承了  Person
class Employee extends Person {
	// department 是 private私有的,意味着它只能在 Employee 类内部访问。
    private department: string;

    constructor(name: string, department: string) {
        super(name)
        this.department = department;
    }
	// getElevatorPitch() 方法是 public 的,可以在任何地方调用。
	// this.name是protected允许的,而Employee是Person的子类,所以可以访问父类的this.name;
    public getElevatorPitch() {
        return `Hello, my name is ${this.name} and I work in ${this.department}.`;
    }
}

// 创建了一个 Employee 的实例 howard。
let howard = new Employee("Howard", "Sales");
// 调用 public 方法,输出:Hello, my name is Howard and I work in Sales.
console.log(howard.getElevatorPitch());

// howard 是一个 实例对象,而不是类内部。
console.log(howard.name); // 错误

构造函数也可以被标记为被保护的protected.这意味着这个类不能包含它的类外被实例化,但是能被继承。

ts 复制代码
	//Person类
	//protected受保护的name
	//protected受保护的构造函数constructor  将传入的参数赋值给实例的name属性。
	// constructor构造函数名称 theName: string参数列表 theName是参数名,string是类型。
	// { this.name = theName; }函数体,将参数赋值给当前实例的name属性。
class Person {
    protected name: string;
    protected constructor(theName: string) { this.name = theName; }
}

// Employee 能够继承 Person
// 私有的department属性类型是string
//constructor的   super(name);子类可以调用父类的protected受保护可以访问父类的构造函数
//public公共的 getElevatorPitch方法 ,可以在任何地方调用。
class Employee extends Person {
    private department: string;

    constructor(name: string, department: string) {
        super(name);
        this.department = department;
    }

    public getElevatorPitch() {
        return `Hello, my name is ${this.name} and I work in ${this.department}.`;
    }
}

let howard = new Employee("Howard", "Sales");
let john = new Person("John"); // 错误: 'Person' 的构造函数是被保护的.

只读的readonly 修饰符

只读属性必须在声明时或构造函数里被初始化。

ts 复制代码
class Octopus {
    readonly name: string;
    readonly numberOfLegs: number = 8;
    constructor (theName: string) {
        this.name = theName;
    }
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // 错误! name 是只读的.

参数属性

ts 复制代码
//参数属性通过给构造函数参数前面添加一个访问限定符来声明。 使用 `private`限定一个
//参数属性会声明并初始化一个私有成员;对于 `public`和 `protected`来说也是一样。
class Octopus {
    readonly numberOfLegs: number = 8;
    constructor(readonly name: string) {
    }
}

存取器 TypeScript支持通过getters/setters来截取对对象成员的访问。

将一个简单的类改写成使用get和set。

ts 复制代码
// 定义一个变量 密码
let passcode = "secret passcode";

//定义Employee类
// private 私有的属性 _fullName ,string类型
class Employee {
  private _fullName: string;
  //  get fullName(): string  这是一个getter(取值器)
  // 当你尝试读取 employee.fullName 时,这个方法会被自动调用。它返回内部的 _fullName 值。
  // 外部看起来像是在访问一个属性,实际上是调用一个方法。
  get fullName(): string {
    return this._fullName;
  }
  //set fullName(newName: string) 这是一个setter(赋值器)
  // 当你尝试给 employee.fullName 赋值时,这个方法会被自动调用。
  // 它会检查 passcode 是否正确:
  // 如果密码正确(等于 "secret passcode"),就允许修改 _fullName。
  // 否则,打印错误信息,拒绝修改。
  set fullName(newName: string) {
    if (passcode && passcode == "secret passcode") {
      this._fullName = newName;
    } else {
      console.log("Error: Unauthorized update of employee!");
    }
  }
}

// 创建一个 Employee 实例。
let employee = new Employee();
// 这行代码触发 setter。
// 此时 passcode 是 "secret passcode",条件成立:
employee.fullName = "Bob Smith";

// employee.fullName 触发 getter,返回 "Bob Smith"。
// "Bob Smith" 是"真值"(truthy),所以 if 条件成立。
// 执行 alert("Bob Smith");,弹出对话框显示姓名。
if (employee.fullName) {
  alert(employee.fullName);
}

静态属性

ts 复制代码
// 定义一个表示"网格"或"坐标系"的类
class Grid {
    // 静态属性:原点坐标,属于类本身,所有实例共享
    // 所有 Grid 实例都使用同一个原点 (0, 0)
    static origin = {x: 0, y: 0};

    // 实例方法:计算给定点到原点的距离
    // 参数 point:一个包含 x 和 y 坐标的对象
    calculateDistanceFromOrigin(point: {x: number; y: number;}) {
        // 计算横向距离(点的 x 坐标 - 原点 x 坐标)
        let xDist = (point.x - Grid.origin.x);
        // 计算纵向距离(点的 y 坐标 - 原点 y 坐标)
        let yDist = (point.y - Grid.origin.y);

        // 使用勾股定理计算欧几里得距离(直线距离)
        // Math.sqrt(xDist² + yDist²) 得到原始距离
        // 然后除以 this.scale,表示"缩放后的距离"
        // 注意:这里的除法可能用于模拟不同单位(如像素转厘米)或分辨率
        return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
    }

    // 构造函数:接收一个 scale 参数
    // public scale: number 表示:
    //   1. 声明一个公共的实例属性 `scale`
    //   2. 在创建实例时自动赋值
    // 相当于:
    //   public scale: number;
    //   constructor(scale: number) { this.scale = scale; }
    constructor(public scale: number) { }
}

// 创建两个 Grid 实例,具有不同的缩放因子
let grid1 = new Grid(1.0);  // 1x 缩放:距离不缩放
let grid2 = new Grid(5.0);  // 5x 缩放:距离除以 5

// 计算点 (10,10) 到原点的距离,并输出
// grid1: 原始距离 ≈14.142,除以 1 → 输出 ≈14.142
console.log(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));

// grid2: 原始距离 ≈14.142,除以 5 → 输出 ≈2.828
console.log(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));

抽象类

abstract 关键字是用于定义收藏类和抽象类内部定义抽象方法。

ts 复制代码
//abstract表示这是一个抽象类
abstract class Animal {
	// abstract makeSound(): void;这是一个抽象方法;
	//(): void 表示:没有参数没有返回值(或返回 undefined)
    abstract makeSound(): void;
	// move这是一个普通方法(具体方法)
    move(): void {
        console.log('roaming the earch...');
    }
}
ts 复制代码
// 抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。 
// 抽象方法的语法与接口方法相似。
// 两者都是定义方法签名但不包含方法体。
// 然而,抽象方法必须包含 abstract关键字并且可以包含访问修饰符。


//定义一个Department的抽象类
abstract class Department {
	//构造函数:接收一个 name 参数,并自动创建公共属性 this.name
    constructor(public name: string) {
    }
	// 具体方法:打印部门名称
    // 所有子类都可以继承并使用这个方法
    printName(): void {
        console.log('Department name: ' + this.name);
    }
	 // 抽象方法:必须在子类中实现
	 // 当前类不提供具体实现,只是"声明"这个方法必须存在
    abstract printMeeting(): void; // 必须在派生类中实现
}

//定义一个子类AccountingDepartment继承Department
class AccountingDepartment extends Department {
	// 子类构造函数
    constructor() {
		 // 必须先调用 super(),才能使用 this
		// super() 调用父类构造函数,传入具体的部门名称
        super('Accounting and Auditing'); // 在派生类的构造函数中必须调用 super()
    }
	// 实现父类的抽象方法
    printMeeting(): void {
        console.log('The Accounting Department meets each Monday at 10am.');
    }
	// 子类特有的方法:生成报告
    // 这个方法在父类 Department 中不存在
    generateReports(): void {
        console.log('Generating accounting reports...');
    }
}

// 声明一个变量,类型为 Department(抽象类)
let department: Department; 

// 错误!不能实例化抽象类
department = new Department(); 
// 编译错误:Cannot create an instance of an abstract class.

// 正确!可以实例化具体的子类,并赋值给抽象类型的变量
department = new AccountingDepartment(); 

// 正确!printName() 在 Department 中定义,可以调用
department.printName(); 
// 输出: Department name: Accounting and Auditing

// 正确!printMeeting() 是抽象方法,但 AccountingDepartment 已实现
department.printMeeting(); 
// 输出: The Accounting Department meets each Monday at 10am.

// 错误!generateReports() 不在 Department 类中声明
department.generateReports(); 
// 编译错误:Property 'generateReports' does not exist on type 'Department'.
高级技巧

构造函数

ts 复制代码
// 创建一个 Greeter 类
class Greeter {
    // 声明一个实例属性:greeting,类型为 string
    greeting: string;

    // 构造函数:接收一个参数 message(类型为 string)
    // 在创建实例时被调用,用于初始化 this.greeting
    constructor(message: string) {
        this.greeting = message; // 把传入的 message 赋值给 this.greeting
    }

    // 实例方法:greet()
    // 返回一个字符串:"Hello, " + 当前实例的 greeting 属性值
    greet() {
        return "Hello, " + this.greeting;
    }
}

// 声明一个变量 greeter,类型是 Greeter 类
let greeter: Greeter;

// 创建 Greeter 类的一个实例,并传入参数 "world"
// 此时 constructor 被调用,this.greeting = "world"
greeter = new Greeter("world");

// 调用实例的 greet() 方法,并将返回值打印到控制台
console.log(greeter.greet());
ts 复制代码
// 定义一个名为 Greeter 的类
class Greeter {
    // 静态属性:standardGreeting
    // 属于类本身,所有实例共享
    // 默认问候语,当实例没有设置 greeting 时使用
    static standardGreeting = "Hello, there";

    // 实例属性:greeting
    // 每个 Greeter 实例可以有自己的 greeting 值
    // 类型为 string
    greeting: string;

    // 实例方法:greet()
    // 根据当前实例的 greeting 值返回不同的问候语
    greet() {
        // 判断当前实例是否有 greeting 属性值
        if (this.greeting) {
            // 如果有 greeting,返回 "Hello, " + greeting
            return "Hello, " + this.greeting;
        } else {
            // 如果没有 greeting(即 undefined 或空字符串)
            // 返回类的静态默认问候语
            return Greeter.standardGreeting;
        }
    }
}

// 声明一个变量 greeter1,类型为 Greeter
let greeter1: Greeter;
// 创建 Greeter 的实例,但没有传入 greeting
// 此时 this.greeting 为 undefined
greeter1 = new Greeter();
// 调用 greet() 方法
// 因为 this.greeting 不存在,所以返回静态属性 Greeter.standardGreeting
console.log(greeter1.greet()); // 输出: Hello, there

// 声明一个变量 greeterMaker,类型为 "Greeter 类本身"
// typeof Greeter 表示类的类型(构造函数的类型),而不是实例的类型
let greeterMaker: typeof Greeter = Greeter;

// 通过 greeterMaker 修改静态属性 standardGreeting
// 因为 greeterMaker 指向 Greeter 类,所以这等价于:
// Greeter.standardGreeting = "Hey there!";
greeterMaker.standardGreeting = "Hey there!";

// 创建一个新的实例 greeter2
// 使用 greeterMaker 作为构造函数(等价于 new Greeter())
let greeter2: Greeter = new greeterMaker();
// 调用 greet() 方法
// 此时 Greeter.standardGreeting 已被修改为 "Hey there!"
// 因为 greeter2.greeting 也是 undefined,所以返回新的静态值
console.log(greeter2.greet()); // 输出: Hey there!

把类当做接口使用

ts 复制代码
// 定义一个类 Point(点)
// 表示二维平面上的一个点,有 x 和 y 坐标
class Point {
    x: number;  // x 坐标,类型为 number
    y: number;  // y 坐标,类型为 number
}

// 定义一个接口 Point3d(三维点)
// 使用 `extends` 继承自 Point 类
// 表示:Point3d 是一个 Point,并且额外有一个 z 坐标
interface Point3d extends Point {
    z: number;  // z 坐标,类型为 number(第三维)
}

// 声明一个变量 point3d,类型为 Point3d
// 创建一个对象字面量 {x: 1, y: 2, z: 3} 并赋值给它
let point3d: Point3d = {x: 1, y: 2, z: 3};

// 这个赋值是合法的,因为:
// 对象有 x: number, y: number(满足 Point 的结构)
// 还有 z: number(满足 Point3d 的额外要求)

总概: typeScript 类(Classes)------ 官方核心概念总概 TypeScript 的类是对 JavaScript ES6 类的超集,在原有语法基础上增加了 类型系统 和 面向对象高级特性,让开发更安全、更可维护。

  1. 基本语法(ES6 + 类型)
ts 复制代码
class Point {
    x: number;  // 实例属性,带类型
    y: number;

    // 构造函数
    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }

    // 实例方法
    distance(): number {
        return Math.sqrt(this.x ** 2 + this.y ** 2);
    }
}

特点:

支持 constructor、methods、properties 所有成员都可以添加类型注解(: number 等) 2. 访问修饰符(Access Modifiers) 控制类成员的可访问性:

修饰符 含义 public 默认,任何地方可访问 ✅ private 只能在类内部访问 ❌ 子类/外部不可访问 protected 类内部 + 子类可访问,外部不可

ts 复制代码
class Animal {
    private name: string;        // 只能在 Animal 内部使用
    protected age: number;       // 子类可以访问
    public species: string;      // 任何人都能访问

    constructor(name: string, age: number, species: string) {
        this.name = name;
        this.age = age;
        this.species = species;
    }
}

编译后这些修饰符会消失(变成普通 JS),但 TS 在编译时做类型检查。

  1. 继承(Inheritance) ------ extends 支持单继承,子类可重写父类方法。
ts 复制代码
class Dog extends Animal {
    constructor(name: string, age: number) {
        super(name, age, "Dog"); // 调用父类构造函数
    }

    // 重写方法
    protected ageUp() {
        this.age += 1; // ✅ 可访问 protected 成员
    }
}
  1. 参数属性(Parameter Properties) 简化构造函数写法,一行声明并初始化属性。
ts 复制代码
class Person {
    // 一行搞定:声明 + 赋值 + 访问控制
    constructor(public name: string, private id: number) {
        // this.name = name;
        // this.id = id;
        // 自动生成
    }
}

等价于:

ts 复制代码
class Person {
    public name: string;
    private id: number;
    constructor(name: string, id: number) {
        this.name = name;
        this.id = id;
    }
}
  1. 存取器(Getters / Setters) 控制属性的读写逻辑。
ts 复制代码
class BankAccount {
    private _balance: number = 0;

    get balance(): number {
        return this._balance;
    }

    set balance(amount: number) {
        if (amount < 0) {
            throw new Error("Balance cannot be negative");
        }
        this._balance = amount;
    }
}

const account = new BankAccount();
account.balance = 100; // 调用 setter
console.log(account.balance); // 调用 getter

需要设置 tsconfig.json 中 "target": "ES5" 或更高。

  1. 静态成员(Static Members) 属于类本身,不属于任何实例。
ts 复制代码
class MathUtils {
    static PI = 3.14159;

    static circleArea(radius: number): number {
        return this.PI * radius ** 2;
    }
}

console.log(MathUtils.PI);             
console.log(MathUtils.circleArea(5));  
  1. 抽象类(Abstract Classes) 用于定义"模板",不能被实例化,只能被继承。
ts 复制代码
abstract class Animal {
    abstract makeSound(): void; // 子类必须实现

    move(): void {
        console.log("Moving...");
    }
}

class Cat extends Animal {
    makeSound(): void {
        console.log("Meow!");
    }
}

适合用于框架设计、基类约束。

  1. this 类型(Fluent Interface) 方法返回 this,支持链式调用。
ts 复制代码
class Calculator {
    value: number = 0;

    add(n: number): this {
        this.value += n;
        return this;
    }

    multiply(n: number): this {
        this.value *= n;
        return this;
    }
}

new Calculator().add(5).multiply(2); // 链式调用 9. 类与接口(Class & Interface) 类可以实现(implements)一个或多个接口,确保结构合规。

ts 复制代码
interface Drawable {
    draw(): void;
}

class Circle implements Drawable {
    draw() {
        console.log("Drawing a circle");
    }
}

接口定义"契约",类负责实现。

  1. 高级:typeof Class 与 构造函数类型
ts 复制代码
let ctor: typeof Point = Point; // ctor 是"类本身"的类型
let p = new ctor(1, 2);         // 可以 new

用于工厂模式、依赖注入等高级场景。

总结:TypeScript 类的五大优势 特性 作用 类型系统 属性、方法、参数都有类型,减少运行时错误 访问控制 private/protected 提高封装性 继承与多态 支持面向对象设计 抽象类 + 接口 实现复杂架构和约束 编译时检查 开发阶段发现问题,提升代码质量

相关推荐
xiguolangzi5 分钟前
vue3 字体管理
前端
伍华聪21 分钟前
基于Vant4+Vue3+TypeScript的H5移动前端
前端
Nayana23 分钟前
axios-取消重复请求--CancelToken&AbortController
前端·axios
大舔牛30 分钟前
网站性能优化:小白友好版详解
前端·面试
转转技术团队38 分钟前
你的H5页面在折叠屏上适配了吗?
前端
北辰浮光1 小时前
[Web数据控制]浏览器中cookie、localStorage和sessionStorage
前端·vue.js·typescript
Dolphin_海豚1 小时前
charles proxying iphone
前端·ios