静态成员
概述
静态成员(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..."静态成员与访问修饰符
静态成员也可以使用访问修饰符(public、private、protected):
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指向类本身,而不是实例 - 实例方法可以通过类名访问静态成员
- 静态成员适合用于工具方法、常量、计数器等场景
- 静态成员也可以使用访问修饰符(
public、private、protected)
注意
- 静态方法中不能直接使用
this访问实例成员 - 实例方法中不能使用
this访问静态成员,应该使用类名 - 静态成员在类加载时初始化,而不是在创建实例时初始化
- 静态成员是共享的,修改会影响所有实例
- 不能通过实例访问静态成员,必须通过类名访问
- 静态方法不能是抽象方法(abstract)
重要
- 静态成员是面向对象编程中的重要概念,理解静态成员对于设计工具类、单例模式等非常重要
- 合理使用静态成员可以避免创建不必要的实例,提高代码效率
- 静态成员适合用于与类相关但不依赖于实例的功能
- 过度使用静态成员可能导致代码难以测试和维护
- 静态成员在多线程环境中需要特别注意线程安全问题(在 JavaScript/TypeScript 中通常不是问题)
信息
静态成员的应用场景:
工具类:提供不依赖于实例的工具方法
MathUtils.add(),StringUtils.capitalize()- 不需要创建实例,直接使用类方法
单例模式:确保类只有一个实例
- 使用私有构造函数和静态实例
- 通过静态方法获取唯一实例
工厂模式:创建对象的工厂方法
ProductFactory.createProduct()- 封装对象创建逻辑
常量定义:定义与类相关的常量
Config.API_URL,Constants.MAX_SIZE- 所有实例共享的常量值
计数器/统计:跟踪类的使用情况
User.totalUsers,Order.nextId- 跨实例共享的计数数据
静态成员 vs 实例成员:
| 特性 | 静态成员 | 实例成员 |
|---|---|---|
| 访问方式 | 通过类名 | 通过实例 |
| 内存位置 | 类本身 | 每个实例独立 |
| 初始化时机 | 类加载时 | 创建实例时 |
| 共享性 | 所有实例共享 | 每个实例独立 |
this 指向 | 类本身 | 实例本身 |
| 适用场景 | 工具方法、常量 | 实例数据、行为 |
设计建议:
- 如果功能不依赖于实例状态,考虑使用静态成员
- 如果功能需要访问或修改实例状态,使用实例成员
- 工具类通常全部使用静态成员
- 领域模型类通常使用实例成员,静态成员用于辅助功能