本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
在 ArkTS 语言中,变量修饰符主要分为以下几类,每个修饰符都有其特定的作用和使用场景:
1. 访问修饰符
控制变量或方法的访问权限。
修饰符 | 作用 | 示例 |
---|---|---|
public | 默认修饰符,允许在任何地方访问 | public name: string = "Alice"; |
private | 仅在当前类内部可访问 | private _age: number = 20; |
protected | 在当前类及其子类中可访问 | protected salary: number = 5000; |
示例:
class Person {
public name: string; // 公开属性
private _id: number; // 私有属性
protected age: number; // 受保护属性
constructor(name: string, id: number) {
this.name = name;
this._id = id;
}
}
2. 只读修饰符
修饰符 | 作用 | 示例 |
---|---|---|
readonly | 变量只能在声明时或构造函数中初始化,之后不可修改 | readonly PI: number = 3.14; |
示例:
class Circle {
readonly PI: number = 3.14159;
radius: number;
constructor(radius: number) {
this.radius = radius;
// this.PI = 3.14; // 错误!readonly 变量不可二次赋值
}
}
3. 静态修饰符
修饰符 | 作用 | 示例 |
---|---|---|
static | 变量或方法属于类本身,而非实例 | static count: number = 0; |
示例:
class Counter {
static count: number = 0; // 静态变量
static increment() { // 静态方法
Counter.count++;
}
}
console.log(Counter.count); // 直接通过类名访问
4. 类型修饰符
修饰符 | 作用 | 示例 |
---|---|---|
const | 定义常量,编译时常量(ArkTS 中较少使用,通常用 readonly 替代) | const MAX_SIZE: number = 100; |
let | 定义块级作用域变量(默认变量声明方式) | let message: string = "Hello"; |
var | 函数作用域变量(不推荐,ArkTS 优先用 let ) | var oldValue: number = 10; |
let
和 var
的关键区别在于作用域。let
是块级作用域({}
内有效),而 var
是函数作用域(整个函数内有效)。优先使用 let
可以避免变量泄露到全局或外层作用域,从而减少命名冲突和意外修改。
问题示例:var
的变量提升与污染:
function exampleVar() {
if (true) {
var value = 10; // var 会提升到函数作用域
console.log("Inner:", value); // 输出 10
}
console.log("Outer:", value); // 也能访问到 value(污染外层)
}
exampleVar();
// 输出:
// Inner: 10
// Outer: 10
问题:var
声明的 value
泄露到了整个 exampleVar
函数作用域,即使它在 if
块中定义。
修复方案:使用 let
块级作用域
function exampleLet() {
if (true) {
let value = 10; // let 仅在 {} 块内有效
console.log("Inner:", value); // 输出 10
}
console.log("Outer:", value); // 报错!value 未定义
}
exampleLet();
// 输出:
// Inner: 10
// Uncaught ReferenceError: value is not defined
优势:
value
仅在if
块内有效,不会污染外层作用域。- 避免与其他代码中的
value
变量冲突。
更复杂的场景对比
var
的陷阱:循环中的变量泄露
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 输出 3, 3, 3(全部指向同一个 i)
}
原因:var i
属于函数作用域,循环结束后 i
的值为 3,所有 setTimeout
回调共享同一个 i
。
let
的块级作用域修复
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 输出 0, 1, 2
}
原因:每次循环 let i
会创建一个新的块级作用域变量,setTimeout
回调捕获的是各自的 i
。
5. 其他特殊修饰符
修饰符 | 作用 | 示例 |
---|---|---|
abstract | 抽象类/方法,需子类实现 | abstract class Shape { abstract area(): number; } |
override | 表示方法覆盖父类实现 | override toString(): string { return "Custom"; } |
示例:
abstract class Animal {
abstract makeSound(): void; // 抽象方法
}
class Dog extends Animal {
override makeSound() { // 必须实现抽象方法
console.log("Woof!");
}
}
关键区别总结
修饰符 | 作用域 | 可变性 | 典型用途 |
---|---|---|---|
public | 全局 | 可修改 | 类公开属性 |
private | 类内部 | 可修改 | 内部状态隐藏 |
readonly | 全局/类 | 不可修改 | 常量或初始化后不变的属性 |
static | 类级别 | 可修改 | 全局计数器或工具方法 |
let | 块级作用域 | 可修改 | 局部变量 |
何时使用哪种修饰符?
- 需要封装数据 →
private
/protected
- 定义常量 →
readonly
- 共享类级别数据 →
static
- 覆盖父类方法 →
override
- 避免全局污染 → 优先用
let
而非var
ArkTS 的修饰符设计沿袭了 TypeScript 的特性,但更强调静态类型安全和面向对象规范。实际开发中应优先使用 let
、readonly
和访问控制修饰符(public
/private
)来保证代码的可维护性。