TypeScript 类的静态成员与静态方法

本文献给:

已掌握 TypeScript 类基础、继承、多态、抽象类等知识的开发者。本文将带你学习类的静态成员(static 属性)和静态方法,包括访问限制、与实例成员的区别,以及工具类设计中的典型应用。

你将学到:

  1. 静态属性与静态方法的定义
  2. 静态成员与实例成员的区别
  3. 静态成员的访问限制(public/private/protected
  4. 静态成员在继承中的行为
  5. 工具类与工厂模式的静态方法设计

目录

一、静态成员的定义

使用 static 关键字定义类的静态属性和静态方法。静态成员属于类本身,而不是类的实例。

typescript 复制代码
class Circle {
    static pi: number = 3.14159;
    
    static calculateArea(radius: number): number {
        return this.pi * radius * radius;
    }
    
    radius: number;
    constructor(radius: number) {
        this.radius = radius;
    }
    
    getArea(): number {
        return Circle.calculateArea(this.radius);
    }
}

console.log(Circle.pi);                    // 3.14159
console.log(Circle.calculateArea(5));      // 78.53975

const c = new Circle(5);
console.log(c.getArea());                  // 78.53975
// console.log(c.pi);                      // ❌ 实例不能访问静态属性

静态成员通过类名直接访问,实例无法访问静态成员(但可以通过 this.constructor 间接访问)。

二、静态方法与实例方法的区别

特性 静态方法 实例方法
归属 类本身 类的实例
调用方式 ClassName.method() instance.method()
访问实例成员 不能直接访问(无 this 指向实例) 可以访问实例成员
访问静态成员 可以(通过 this 或类名) 可以(通过类名)
使用场景 工具函数、工厂方法、单例模式 操作实例数据
typescript 复制代码
class Example {
    static staticProp = 0;
    instanceProp = 1;
    
    static staticMethod() {
        console.log(this.staticProp);  // OK
        // console.log(this.instanceProp);  // ❌ 静态方法中不能访问实例属性
    }
    
    instanceMethod() {
        console.log(Example.staticProp);  // OK
        console.log(this.instanceProp);   // OK
    }
}

三、静态成员的访问修饰符

静态成员可以结合 publicprivateprotected 使用,控制访问范围。

typescript 复制代码
class Database {
    private static instance: Database;
    private constructor() {}
    
    static getInstance(): Database {
        if (!Database.instance) {
            Database.instance = new Database();
        }
        return Database.instance;
    }
    
    query(sql: string) {
        console.log(`Executing: ${sql}`);
    }
}

const db = Database.getInstance();
db.query("SELECT * FROM users");
// const db2 = new Database();  // ❌ 构造函数私有

3.1 protected 静态成员

protected static 可以在子类中访问。

typescript 复制代码
class Base {
    protected static config = { version: "1.0" };
}

class Derived extends Base {
    static showConfig() {
        console.log(this.config);  // OK
    }
}

Derived.showConfig();  // { version: "1.0" }

四、静态成员在继承中的行为

静态成员也会被继承,子类可以访问父类的静态成员。

typescript 复制代码
class Parent {
    static value = 10;
    static getValue() {
        return this.value;
    }
}

class Child extends Parent {
    static value = 20;  // 覆盖
}

console.log(Parent.getValue());  // 10
console.log(Child.getValue());   // 20(静态方法中的 this 指向调用者)

静态方法中的 this 指向调用该方法的类(而不是定义时的类),因此子类可以覆盖静态属性并影响方法返回值。

4.1 类名与 this 的区别

typescript 复制代码
class A {
    static name = "A";
    static getName() {
        return this.name;
    }
    static getNameHard() {
        return A.name;  // 始终返回 A.name
    }
}

class B extends A {
    static name = "B";
}

console.log(B.getName());      // "B"(this 指向 B)
console.log(B.getNameHard());  // "A"(固定使用 A.name)

五、常见使用场景

5.1 工具类

将相关工具函数组织为静态方法,无需实例化。

typescript 复制代码
class MathUtils {
    static clamp(value: number, min: number, max: number): number {
        return Math.min(max, Math.max(min, value));
    }
    
    static randomRange(min: number, max: number): number {
        return min + Math.random() * (max - min);
    }
    
    static degToRad(deg: number): number {
        return deg * Math.PI / 180;
    }
}

console.log(MathUtils.clamp(150, 0, 100));   // 100

5.2 工厂方法

静态方法作为工厂创建实例,可以封装复杂的创建逻辑或缓存。

typescript 复制代码
class User {
    private constructor(public id: number, public name: string) {}
    
    private static cache = new Map<number, User>();
    
    static create(id: number, name: string): User {
        if (this.cache.has(id)) {
            return this.cache.get(id)!;
        }
        const user = new User(id, name);
        this.cache.set(id, user);
        return user;
    }
}

const u1 = User.create(1, "Alice");
const u2 = User.create(1, "Bob");   // 返回缓存的 Alice
console.log(u1 === u2);  // true

5.3 单例模式

确保一个类只有一个实例。

typescript 复制代码
class Logger {
    private static instance: Logger;
    private logs: string[] = [];
    
    private constructor() {}
    
    static getInstance(): Logger {
        if (!Logger.instance) {
            Logger.instance = new Logger();
        }
        return Logger.instance;
    }
    
    log(msg: string) {
        this.logs.push(msg);
        console.log(msg);
    }
    
    getLogs() {
        return [...this.logs];
    }
}

const logger1 = Logger.getInstance();
const logger2 = Logger.getInstance();
console.log(logger1 === logger2);  // true

六、常见错误与注意事项

6.1 静态方法中访问实例成员

typescript 复制代码
class Demo {
    name = "demo";
    static test() {
        // console.log(this.name);  // ❌ 静态方法中 this 是类,没有 name
    }
}

如果需要访问实例,可以将实例作为参数传入。

6.2 实例中访问静态成员时混淆

实例方法中访问静态成员推荐使用类名,而不是 this,因为 this 可能被覆盖(尤其在继承中)。

typescript 复制代码
class Parent {
    static value = 10;
    getStatic() {
        return (this.constructor as any).value;  // 不推荐,麻烦且容易出错
    }
    getStaticBetter() {
        return Parent.value;  // 明确使用类名
    }
}

6.3 子类覆盖静态属性时影响父类静态方法中的 this

如果父类静态方法使用 this.xxx,子类覆盖静态属性后,调用子类该方法会得到子类属性值。这可能符合预期,也可能不是。根据需求选择使用 ClassName 还是 this

6.4 在静态块中初始化(ES2022+)

TypeScript 支持静态块(需 target ES2022 或更高),用于复杂静态初始化。

typescript 复制代码
class Config {
    static settings: Record<string, string>;
    static {
        // 静态块在类初始化时执行
        this.settings = JSON.parse(localStorage.getItem("config") || "{}");
    }
}

6.5 泛型类中的静态成员

静态成员不能引用类的泛型类型参数,因为静态成员属于类而非实例,类型参数在实例化时才确定。

typescript 复制代码
class Generic<T> {
    // static value: T;  // ❌ 静态成员不能使用泛型参数
}

七、综合示例

typescript 复制代码
// 任务管理器:使用静态成员管理全局任务计数和配置
class Task {
    private static taskCount = 0;
    private static readonly MAX_TASKS = 100;
    
    static get count() {
        return Task.taskCount;
    }
    
    static canCreate(): boolean {
        return Task.taskCount < Task.MAX_TASKS;
    }
    
    static reset() {
        Task.taskCount = 0;
    }
    
    private id: number;
    constructor(public title: string) {
        if (!Task.canCreate()) {
            throw new Error("Task limit reached");
        }
        this.id = ++Task.taskCount;
    }
    
    getId() {
        return this.id;
    }
}

// 子类继承静态成员
class UrgentTask extends Task {
    static override canCreate(): boolean {
        return Task.count < 20;  // 紧急任务限制更严格
    }
    
    constructor(title: string, public priority: number) {
        super(title);
    }
}

try {
    for (let i = 0; i < 50; i++) {
        new Task(`Task ${i}`);
    }
} catch (e) {
    console.log(e.message);  // "Task limit reached"
}

console.log(Task.count);    // 100
Task.reset();
console.log(Task.count);    // 0

// 工厂静态方法
class Point {
    constructor(public x: number, public y: number) {}
    
    static fromPolar(radius: number, angle: number): Point {
        return new Point(radius * Math.cos(angle), radius * Math.sin(angle));
    }
    
    static fromObject(obj: { x: number; y: number }): Point {
        return new Point(obj.x, obj.y);
    }
}

const p1 = Point.fromPolar(5, Math.PI / 4);
const p2 = Point.fromObject({ x: 10, y: 20 });
console.log(p1, p2);

八、小结

概念 语法示例 说明
静态属性 static count = 0 属于类本身的属性
静态方法 static getCount() { return this.count; } 属于类本身的方法
访问静态成员 ClassName.property 在外部和实例方法中通过类名访问
继承中的静态成员 子类可访问/覆盖父类静态成员 静态方法中的 this 指向子类
私有静态成员 private static instance 用于单例模式
使用场景 工具方法、工厂、缓存、单例 无需实例化的功能

觉得文章有帮助?别忘了:

👍 点赞 👍 -- 给我一点鼓励

⭐ 收藏 ⭐ -- 方便以后查看

🔔 关注 🔔 -- 获取更新通知


标签: #TypeScript #静态成员 #静态方法 #面向对象 #学习笔记 #前端开发

相关推荐
代码煮茶9 小时前
React 组件封装方法论 —— 以 Todo App 为例
javascript·react.js
任沫10 小时前
Agent之Function Call
javascript·人工智能·go
默_笙11 小时前
🛬 我让 AI 帮我写了一个打飞机游戏,结果 Canvas 把我整不会了
前端·javascript
梯度不陡11 小时前
AI 到底能不能从零写软件?ProgramBench 和 RepoZero 给出了两种答案
前端·javascript·面试
胡萝卜术13 小时前
滑动窗口最大值:从暴力到单调队列,层层优化全解析
前端·javascript·面试
kyriewen14 小时前
2026 年了,这 6 个 npm 包可以卸载了——浏览器原生 API 已经能替代
前端·javascript·npm
铁皮饭盒15 小时前
bun直接tsx,优雅!
javascript·后端
_柳青杨17 小时前
一文吃透 Node.js 事件循环:从原理到 Node 20+ 重大变更
javascript·后端
JieE2121 天前
LeetCode 101. 对称二叉树|JS 递归 + 迭代双解法,彻底搞懂镜像判断
javascript·算法
冬奇Lab1 天前
AI Workflow 定义的四次演进:从 Markdown 到 JS 脚本,再到分布式多 Agent
javascript·人工智能·agent