在 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 提高封装性 继承与多态 支持面向对象设计 抽象类 + 接口 实现复杂架构和约束 编译时检查 开发阶段发现问题,提升代码质量

相关推荐
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端
爱敲代码的小鱼8 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax