Skip to content

静态成员

概述

静态成员(Static Members)是属于类本身而不是类实例的成员。使用 static 关键字声明的属性和方法可以直接通过类名访问,而不需要创建类的实例。静态成员在类的所有实例之间共享,通常用于定义工具方法、常量、计数器等与类相关但不依赖于实例的数据和行为。理解静态成员对于设计工具类、单例模式、工厂模式等设计模式非常重要。

基本语法

静态属性

使用 static 关键字声明静态属性,静态属性属于类本身,所有实例共享同一个静态属性:

typescript
class Counter {
  // 静态属性
  static count: number = 0;
  
  // 实例属性
  name: string;
  
  constructor(name: string) {
    this.name = name;
  }
  
  // 实例方法可以访问静态属性
  increment(): void {
    Counter.count++;  // 通过类名访问静态属性
    console.log(`${this.name}: Count is now ${Counter.count}`);
  }
}

// 直接通过类名访问静态属性
console.log(Counter.count);  // 0

const counter1 = new Counter("Counter 1");
const counter2 = new Counter("Counter 2");

counter1.increment();  // "Counter 1: Count is now 1"
counter2.increment();  // "Counter 2: Count is now 2"

// 所有实例共享同一个静态属性
console.log(Counter.count);  // 2

静态方法

使用 static 关键字声明静态方法,静态方法可以直接通过类名调用,不需要创建实例:

typescript
class MathUtils {
  // 静态方法:计算两个数的和
  static add(a: number, b: number): number {
    return a + b;
  }
  
  // 静态方法:计算两个数的乘积
  static multiply(a: number, b: number): number {
    return a * b;
  }
  
  // 静态方法:计算圆的面积
  static circleArea(radius: number): number {
    return Math.PI * radius * radius;
  }
  
  // 静态方法:生成随机数
  static random(min: number, max: number): number {
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }
}

// 直接通过类名调用静态方法,不需要创建实例
console.log(MathUtils.add(5, 3));              // 8
console.log(MathUtils.multiply(4, 7));          // 28
console.log(MathUtils.circleArea(5));          // 78.53981633974483
console.log(MathUtils.random(1, 100));         // 随机数 1-100

// ❌ 错误:不能通过实例调用静态方法
// const utils = new MathUtils();
// utils.add(5, 3);  // Error: Property 'add' does not exist on type 'MathUtils'

静态成员访问规则

静态成员和实例成员有不同的访问规则:

typescript
class Example {
  // 静态属性
  static staticProp: string = "static";
  
  // 实例属性
  instanceProp: string = "instance";
  
  // 静态方法
  static staticMethod(): void {
    console.log("Static method");
    // 静态方法可以访问静态成员
    console.log(this.staticProp);  // ✅ 可以访问静态属性
    // console.log(this.instanceProp);  // ❌ 错误:不能访问实例成员
  }
  
  // 实例方法
  instanceMethod(): void {
    console.log("Instance method");
    // 实例方法可以访问实例成员和静态成员
    console.log(this.instanceProp);        // ✅ 可以访问实例属性
    console.log(Example.staticProp);      // ✅ 可以访问静态属性(通过类名)
    Example.staticMethod();                // ✅ 可以调用静态方法(通过类名)
  }
}

// 访问静态成员
Example.staticMethod();  // ✅ 通过类名调用
console.log(Example.staticProp);  // ✅ 通过类名访问

// 访问实例成员
const example = new Example();
example.instanceMethod();  // ✅ 通过实例调用
console.log(example.instanceProp);  // ✅ 通过实例访问

注意

  • 静态方法中不能使用 this 访问实例成员,因为 this 在静态方法中指向类本身
  • 实例方法可以通过类名访问静态成员
  • 静态成员在类加载时初始化,而不是在创建实例时初始化

静态成员初始化

静态属性初始化

静态属性可以在声明时初始化,也可以在静态块中初始化:

typescript
class Config {
  // 方式 1:声明时初始化
  static apiUrl: string = "https://api.example.com";
  static timeout: number = 5000;
  
  // 方式 2:延迟初始化(使用 undefined)
  static maxRetries: number | undefined;
  
  // 静态方法初始化
  static initialize(): void {
    Config.maxRetries = 3;
  }
}

console.log(Config.apiUrl);  // "https://api.example.com"
Config.initialize();
console.log(Config.maxRetries);  // 3

静态块(Static Blocks)

TypeScript 支持静态块(Static Blocks),用于在类加载时执行初始化代码:

typescript
class Database {
  static connectionString: string;
  static isConnected: boolean;
  
  // 静态块:在类加载时执行
  static {
    // 从环境变量或配置文件读取
    Database.connectionString = process.env.DB_URL || "localhost:5432";
    Database.isConnected = false;
    console.log("Database class initialized");
  }
  
  static connect(): void {
    console.log(`Connecting to ${Database.connectionString}...`);
    Database.isConnected = true;
  }
  
  static disconnect(): void {
    Database.isConnected = false;
    console.log("Disconnected from database");
  }
}

// 类加载时静态块会自动执行
// 输出: "Database class initialized"

Database.connect();  // "Connecting to localhost:5432..."

静态成员与访问修饰符

静态成员也可以使用访问修饰符(publicprivateprotected):

typescript
class Logger {
  // 公共静态属性
  public static logLevel: string = "info";
  
  // 私有静态属性
  private static logCount: number = 0;
  
  // 受保护静态属性
  protected static maxLogs: number = 1000;
  
  // 公共静态方法
  public static log(message: string): void {
    Logger.logCount++;
    if (Logger.logCount <= Logger.maxLogs) {
      console.log(`[${Logger.logLevel}] ${message}`);
    } else {
      console.warn("Max logs reached");
    }
  }
  
  // 私有静态方法
  private static incrementCount(): void {
    Logger.logCount++;
  }
  
  // 公共静态方法访问私有静态成员
  public static getLogCount(): number {
    return Logger.logCount;
  }
  
  // 公共静态方法重置计数
  public static reset(): void {
    Logger.logCount = 0;
  }
}

// 可以访问公共静态成员
Logger.log("Application started");  // ✅
console.log(Logger.logLevel);       // ✅ "info"
console.log(Logger.getLogCount());   // ✅ 1

// ❌ 错误:不能访问私有静态成员
// console.log(Logger.logCount);  // Error: Property 'logCount' is private
// Logger.incrementCount();        // Error: Property 'incrementCount' is private

静态成员的继承

子类可以继承父类的静态成员,也可以定义自己的静态成员:

typescript
class Base {
  static baseStaticProp: string = "base static";
  static baseStaticMethod(): void {
    console.log("Base static method");
  }
}

class Derived extends Base {
  static derivedStaticProp: string = "derived static";
  static derivedStaticMethod(): void {
    console.log("Derived static method");
    // 可以访问父类的静态成员
    Base.baseStaticMethod();  // ✅ 通过父类名访问
  }
  
  // 可以重写父类的静态方法
  static baseStaticMethod(): void {
    console.log("Derived overridden static method");
  }
}

// 子类可以访问父类的静态成员
console.log(Derived.baseStaticProp);  // ✅ "base static"
Derived.baseStaticMethod();           // ✅ "Derived overridden static method"

// 子类自己的静态成员
console.log(Derived.derivedStaticProp);  // ✅ "derived static"
Derived.derivedStaticMethod();           // ✅ "Derived static method"

使用示例

示例 1:工具类

typescript
class StringUtils {
  // 静态方法:首字母大写
  static capitalize(str: string): string {
    if (!str) return str;
    return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
  }
  
  // 静态方法:反转字符串
  static reverse(str: string): string {
    return str.split("").reverse().join("");
  }
  
  // 静态方法:检查是否为回文
  static isPalindrome(str: string): boolean {
    const cleaned = str.toLowerCase().replace(/[^a-z0-9]/g, "");
    return cleaned === StringUtils.reverse(cleaned);
  }
  
  // 静态方法:截断字符串
  static truncate(str: string, maxLength: number, suffix: string = "..."): string {
    if (str.length <= maxLength) return str;
    return str.slice(0, maxLength - suffix.length) + suffix;
  }
  
  // 静态方法:生成随机字符串
  static randomString(length: number): string {
    const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    let result = "";
    for (let i = 0; i < length; i++) {
      result += chars.charAt(Math.floor(Math.random() * chars.length));
    }
    return result;
  }
}

// 使用静态方法,不需要创建实例
console.log(StringUtils.capitalize("hello"));        // "Hello"
console.log(StringUtils.reverse("TypeScript"));      // "tpircSepyT"
console.log(StringUtils.isPalindrome("racecar"));    // true
console.log(StringUtils.truncate("This is a long string", 10));  // "This is a..."
console.log(StringUtils.randomString(8));            // 随机8位字符串

示例 2:单例模式

typescript
class AppConfig {
  // 私有静态实例
  private static instance: AppConfig;
  
  // 私有构造函数,防止外部创建实例
  private constructor(
    public appName: string,
    public version: string,
    public environment: string
  ) {}
  
  // 公共静态方法:获取单例实例
  public static getInstance(): AppConfig {
    if (!AppConfig.instance) {
      AppConfig.instance = new AppConfig(
        "MyApp",
        "1.0.0",
        process.env.NODE_ENV || "development"
      );
    }
    return AppConfig.instance;
  }
  
  // 静态方法:获取配置信息
  public static getInfo(): string {
    const config = AppConfig.getInstance();
    return `${config.appName} v${config.version} (${config.environment})`;
  }
}

// 使用单例模式
const config1 = AppConfig.getInstance();
const config2 = AppConfig.getInstance();

console.log(config1 === config2);  // true(同一个实例)

console.log(AppConfig.getInfo());  // "MyApp v1.0.0 (development)"
console.log(config1.appName);      // "MyApp"

// ❌ 错误:不能直接创建实例
// const config = new AppConfig("App", "1.0.0", "prod");  // Error: Constructor is private

示例 3:计数器系统

typescript
class User {
  // 静态属性:用户总数
  private static totalUsers: number = 0;
  
  // 静态属性:用户ID生成器
  private static nextId: number = 1;
  
  // 实例属性
  public readonly id: number;
  public name: string;
  public email: string;
  
  constructor(name: string, email: string) {
    // 分配唯一ID
    this.id = User.nextId++;
    this.name = name;
    this.email = email;
    
    // 增加用户总数
    User.totalUsers++;
  }
  
  // 静态方法:获取用户总数
  public static getTotalUsers(): number {
    return User.totalUsers;
  }
  
  // 静态方法:重置计数器(用于测试)
  public static resetCounters(): void {
    User.totalUsers = 0;
    User.nextId = 1;
  }
  
  // 实例方法:获取用户信息
  public getInfo(): string {
    return `User #${this.id}: ${this.name} (${this.email})`;
  }
}

// 创建用户
const user1 = new User("Alice", "alice@example.com");
const user2 = new User("Bob", "bob@example.com");
const user3 = new User("Charlie", "charlie@example.com");

console.log(user1.getInfo());  // "User #1: Alice (alice@example.com)"
console.log(user2.getInfo());  // "User #2: Bob (bob@example.com)"
console.log(user3.getInfo());  // "User #3: Charlie (charlie@example.com)"

// 通过静态方法获取总数
console.log(User.getTotalUsers());  // 3

示例 4:工厂模式

typescript
interface Product {
  name: string;
  price: number;
  getInfo(): string;
}

class ProductFactory {
  // 静态方法:创建产品
  static createProduct(type: "book" | "electronics" | "clothing", name: string, price: number): Product {
    switch (type) {
      case "book":
        return new Book(name, price);
      case "electronics":
        return new Electronics(name, price);
      case "clothing":
        return new Clothing(name, price);
      default:
        throw new Error(`Unknown product type: ${type}`);
    }
  }
  
  // 静态方法:批量创建产品
  static createProducts(products: Array<{ type: "book" | "electronics" | "clothing"; name: string; price: number }>): Product[] {
    return products.map(p => ProductFactory.createProduct(p.type, p.name, p.price));
  }
}

class Book implements Product {
  constructor(public name: string, public price: number) {}
  
  getInfo(): string {
    return `Book: ${this.name} - $${this.price}`;
  }
}

class Electronics implements Product {
  constructor(public name: string, public price: number) {}
  
  getInfo(): string {
    return `Electronics: ${this.name} - $${this.price}`;
  }
}

class Clothing implements Product {
  constructor(public name: string, public price: number) {}
  
  getInfo(): string {
    return `Clothing: ${this.name} - $${this.price}`;
  }
}

// 使用工厂方法创建产品
const book = ProductFactory.createProduct("book", "TypeScript Guide", 29.99);
const laptop = ProductFactory.createProduct("electronics", "Laptop", 999.99);
const shirt = ProductFactory.createProduct("clothing", "T-Shirt", 19.99);

console.log(book.getInfo());    // "Book: TypeScript Guide - $29.99"
console.log(laptop.getInfo());  // "Electronics: Laptop - $999.99"
console.log(shirt.getInfo());   // "Clothing: T-Shirt - $19.99"

// 批量创建
const products = ProductFactory.createProducts([
  { type: "book", name: "JavaScript Guide", price: 24.99 },
  { type: "electronics", name: "Phone", price: 599.99 }
]);

products.forEach(p => console.log(p.getInfo()));

示例 5:验证工具类

typescript
class Validator {
  // 静态方法:验证邮箱
  static isValidEmail(email: string): boolean {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
  }
  
  // 静态方法:验证手机号(中国)
  static isValidPhone(phone: string): boolean {
    const phoneRegex = /^1[3-9]\d{9}$/;
    return phoneRegex.test(phone);
  }
  
  // 静态方法:验证URL
  static isValidURL(url: string): boolean {
    try {
      new URL(url);
      return true;
    } catch {
      return false;
    }
  }
  
  // 静态方法:验证密码强度
  static isStrongPassword(password: string): boolean {
    // 至少8位,包含大小写字母、数字和特殊字符
    const strongPasswordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
    return strongPasswordRegex.test(password);
  }
  
  // 静态方法:验证身份证号(中国)
  static isValidIDCard(idCard: string): boolean {
    const idCardRegex = /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/;
    return idCardRegex.test(idCard);
  }
  
  // 静态方法:综合验证
  static validate(data: {
    email?: string;
    phone?: string;
    url?: string;
    password?: string;
    idCard?: string;
  }): { isValid: boolean; errors: string[] } {
    const errors: string[] = [];
    
    if (data.email && !Validator.isValidEmail(data.email)) {
      errors.push("Invalid email address");
    }
    
    if (data.phone && !Validator.isValidPhone(data.phone)) {
      errors.push("Invalid phone number");
    }
    
    if (data.url && !Validator.isValidURL(data.url)) {
      errors.push("Invalid URL");
    }
    
    if (data.password && !Validator.isStrongPassword(data.password)) {
      errors.push("Password is not strong enough");
    }
    
    if (data.idCard && !Validator.isValidIDCard(data.idCard)) {
      errors.push("Invalid ID card number");
    }
    
    return {
      isValid: errors.length === 0,
      errors
    };
  }
}

// 使用验证工具
console.log(Validator.isValidEmail("user@example.com"));     // true
console.log(Validator.isValidEmail("invalid-email"));       // false
console.log(Validator.isValidPhone("13812345678"));          // true
console.log(Validator.isValidURL("https://example.com"));    // true
console.log(Validator.isStrongPassword("StrongPass123!"));   // true

const result = Validator.validate({
  email: "user@example.com",
  phone: "13812345678",
  password: "WeakPass"
});

console.log(result.isValid);  // false
console.log(result.errors);   // ["Password is not strong enough"]

类型检查示例

常见错误

typescript
// ❌ 错误:通过实例访问静态成员
class Example {
  static staticMethod(): void {
    console.log("Static method");
  }
}

const example = new Example();
example.staticMethod();
// Error: Property 'staticMethod' does not exist on type 'Example'

// ❌ 错误:在静态方法中使用 this 访问实例成员
class Example {
  instanceProp: string = "instance";
  
  static staticMethod(): void {
    console.log(this.instanceProp);  // 错误:this 在静态方法中指向类本身
    // Error: Property 'instanceProp' does not exist on type 'typeof Example'
  }
}

// ❌ 错误:在实例方法中使用 this 访问静态成员
class Example {
  static staticProp: string = "static";
  
  instanceMethod(): void {
    console.log(this.staticProp);  // 错误:应该使用类名访问
    // Error: Property 'staticProp' does not exist on type 'Example'
  }
}

// ❌ 错误:静态方法不能访问实例属性
class Example {
  instanceProp: string = "instance";
  
  static staticMethod(): void {
    const example = new Example();
    console.log(example.instanceProp);  // ✅ 这样可以,但通常不是好的设计
    // 但直接访问 this.instanceProp 会报错
  }
}

正确写法

typescript
// ✅ 正确:通过类名访问静态成员
class Example {
  static staticProp: string = "static";
  
  static staticMethod(): void {
    console.log(Example.staticProp);  // ✅ 通过类名访问
  }
}

Example.staticMethod();  // ✅ 通过类名调用

// ✅ 正确:在实例方法中通过类名访问静态成员
class Example {
  static staticProp: string = "static";
  instanceProp: string = "instance";
  
  instanceMethod(): void {
    console.log(this.instanceProp);      // ✅ 访问实例属性
    console.log(Example.staticProp);     // ✅ 通过类名访问静态属性
    Example.staticMethod();              // ✅ 通过类名调用静态方法
  }
}

// ✅ 正确:静态方法中访问静态成员
class Example {
  static staticProp: string = "static";
  
  static staticMethod(): void {
    console.log(Example.staticProp);    // ✅ 通过类名访问
    console.log(this.staticProp);        // ✅ 在静态方法中,this 指向类本身
  }
}

// ✅ 正确:使用访问修饰符控制静态成员可见性
class Example {
  public static publicStatic: string = "public";
  private static privateStatic: string = "private";
  protected static protectedStatic: string = "protected";
  
  public static getPrivate(): string {
    return Example.privateStatic;  // ✅ 类内部可以访问私有静态成员
  }
}

console.log(Example.publicStatic);     // ✅ 可以访问
console.log(Example.getPrivate());     // ✅ 通过公共方法访问
// console.log(Example.privateStatic);  // ❌ 错误:私有成员不能外部访问

注意事项

提示

  • 静态成员属于类本身,所有实例共享同一个静态成员
  • 使用 static 关键字声明静态属性和方法
  • 通过类名直接访问静态成员,不需要创建实例
  • 静态方法中 this 指向类本身,而不是实例
  • 实例方法可以通过类名访问静态成员
  • 静态成员适合用于工具方法、常量、计数器等场景
  • 静态成员也可以使用访问修饰符(publicprivateprotected

注意

  • 静态方法中不能直接使用 this 访问实例成员
  • 实例方法中不能使用 this 访问静态成员,应该使用类名
  • 静态成员在类加载时初始化,而不是在创建实例时初始化
  • 静态成员是共享的,修改会影响所有实例
  • 不能通过实例访问静态成员,必须通过类名访问
  • 静态方法不能是抽象方法(abstract)

重要

  • 静态成员是面向对象编程中的重要概念,理解静态成员对于设计工具类、单例模式等非常重要
  • 合理使用静态成员可以避免创建不必要的实例,提高代码效率
  • 静态成员适合用于与类相关但不依赖于实例的功能
  • 过度使用静态成员可能导致代码难以测试和维护
  • 静态成员在多线程环境中需要特别注意线程安全问题(在 JavaScript/TypeScript 中通常不是问题)

信息

静态成员的应用场景

  1. 工具类:提供不依赖于实例的工具方法

    • MathUtils.add(), StringUtils.capitalize()
    • 不需要创建实例,直接使用类方法
  2. 单例模式:确保类只有一个实例

    • 使用私有构造函数和静态实例
    • 通过静态方法获取唯一实例
  3. 工厂模式:创建对象的工厂方法

    • ProductFactory.createProduct()
    • 封装对象创建逻辑
  4. 常量定义:定义与类相关的常量

    • Config.API_URL, Constants.MAX_SIZE
    • 所有实例共享的常量值
  5. 计数器/统计:跟踪类的使用情况

    • User.totalUsers, Order.nextId
    • 跨实例共享的计数数据

静态成员 vs 实例成员

特性静态成员实例成员
访问方式通过类名通过实例
内存位置类本身每个实例独立
初始化时机类加载时创建实例时
共享性所有实例共享每个实例独立
this 指向类本身实例本身
适用场景工具方法、常量实例数据、行为

设计建议

  • 如果功能不依赖于实例状态,考虑使用静态成员
  • 如果功能需要访问或修改实例状态,使用实例成员
  • 工具类通常全部使用静态成员
  • 领域模型类通常使用实例成员,静态成员用于辅助功能

相关链接

基于 VitePress 构建