类、对象与接口
类
ArkTS继承自TypeScript,所以也有类
和接口
的概念。
类的声明
class Person {
// 成员变量在声明时,或者在构造函数中尽量显式初始化
name: string = "";
age: number = 1;
// 构造函数
constructor (x: string, y: number) {
this.name = x;
this.age = y;
}
// 成员方法
show(): string {
return this.name + " " + this.age;
}
}
// 通过new关键字创建类
let p = new Person("lixingyun", 21);
// 输出"lixingyun 21"
console.log(p.show());
// 通过字面量创建类
class Point {
x: number = 0;
y: number = 0;
}
let pt: Point = { x: 42, y: 42 };
// 输出{"x": 42, "y": 42}
console.log(pt);
静态字段
static
关键字将字段声明为静态。
静态字段属于类本身,所有的实例共享一个静态字段。
要访问静态字段,需要使用类名。
class Person {
static numberOfPersons = 0;
constructor() {
Person.numberOfPersons++;
}
}
// 输出0
console.log(Person.numberOfPersons);
getter和setter
class Person {
name: string = "";
_age: number = 1;
get age(): number {
return this._age;
}
set age(x: number) {
if (x < 0) {
throw Error('Invalid age argument');
}
this._age = x;
}
}
let p = new Person();
console.log(p.age);
p.age = 2;
console.log(p.age);
其实不用getter
和setter
,直接调用p._age
也能读取和写入数据。
getter
和setter
主要是作用于存在private
修饰符的变量上。
可见性
public
:修饰的类成员(字段、方法、构造函数),在程序的任何地方都能访问该类的成员。protected
:修饰的类成员(字段、方法、构造函数),修饰的成员允许在派生类中访问。private
:修饰的类成员(字段、方法、构造函数),不能在声明该成员的类之外访问。
构造函数
ArkTS的类声明可以包含用于初始化对象状态的构造函数。
如果未定义构造函数,则会自动创建一个空参数列表的默认构造函数。
// 构造函数的语法:constructor ([parameters]) { ... }
class Point {
x: number = 0;
y: number = 0;
}
// 没有显式地创建构造函数时会自动创建它
let p = new Point();
派生类的构造函数
构造函数函数体的第一条语句,可以使用super
来显式调用父类的构造函数。
class Rectangle {
width: number = 0;
height: number = 0;
constructor(width: number, height: number) {
this.width = width;
this.height = height;
}
public calc(): number {
return this.width * this.height;
}
}
class Square extends Rectangle {
side: number = 0;
// 如果父类显式地定义了构造器,那么子类也必须定义构造器并通过super()引用父类构造器
constructor(side: number) {
super(side, side);
this.side = side;
}
public calc(): number {
return this.side * this.side;
}
}
let r = new Rectangle(10, 2);
// 输出20
console.log(r.calc());
let s = new Square(10);
// 输出100
console.log(s.calc());
构造函数重载
可以创建多个同名但签名不同的构造函数。
class User {
name: string = "";
age: number = 0;
constructor(name: string);
constructor(age: number);
constructor(x: number | string) {
}
}
let u1 = new User("abc");
let u2 = new User(123);
// 输出""
console.log(u1.name);
// 输出0
console.log(u1.age);
对象字面量
对象字面量是一个表达式,可用于创建类实例并提供一些初始值,可以用来代替new
关键字。
class User {
name: string = "";
age: number = 0;
}
function foo(user: User) {
}
let user: User;
// 使用变量的类型
user = {name: 'lixingyun', age: 20};
// 使用参数的类型
foo({name: "wanglin", age: 19});
// 使用返回类型
function bar(): User {
return {name: "xiaoyan", age: 21}
}
// 在数组元素类型或类字段类型中使用
let arr: User[] = [{name: "shihao", age: 22}, {name: "luofeng", age: 20}];
// 输出{"name": "lixingyun", "age": 20}
console.log(user);
// 输出22
console.log(arr[0].age);
Record
类型的对象字面量Record<K, V>
用于将键
类型的属性,映射到值
类型。K
可以是字符串类型或数值类型,而V
可以是任何类型。
// 初始化该类型的值
let map1: Record<string, number> = {
"lixingyun": 20,
"wanglin": 19
}
// 输出20
console.log(map1["lixingyun"]);
// Record<K, V>中的V可以是任何类型
interface PersonInfo {
age: number;
salary: number;
}
let map2: Record<string, PersonInfo> = {
"lixingyun": { age: 20, salary: 10000 },
"wanglin": { age: 19, salary: 20000 }
}
// 输出10000
console.log(map2["lixingyun"].salary);
方法
实例方法
实例方法可以访问静态字段,也可以访问实例字段,包括类的私有字段。
class Rectangle {
private height: number = 0;
private width: number = 0;
constructor(height: number, width: number) {
this.height = height;
this.width = width;
}
public calculateArea(): number {
return this.height * this.width;
}
}
let square = new Rectangle(10, 10);
// 输出100
console.log(square.calculateArea());
静态方法
static
将方法声明为静态,所有的实例共享一个静态方法。
实例变量无法调用静态字段和静态方法的。
class User {
static nickname: string = "不良帅";
public static getName(): string {
return User.nickname;
}
}
// 输出"不良帅"
console.log(User.getName());
let user = new User();
// 错误,实例变量无法调用静态字段和静态方法
user.nickname;
继承
类可以继承另一个类(称为基类
),继承基类
的字段和方法,但不继承其构造函数。
继承类可以定义自己的字段和方法,也可以覆盖其基类
定义的方法。
class Person {
name: string = "";
private _age = 0;
get age(): number {
return this._age;
}
}
class Employee extends Person {
salary: number = 0;
calculateTaxes(): number {
return this.salary * 0.15;
}
}
let employee = new Employee();
employee.salary = 10000;
// 输出0
console.log(employee.age);
// 输出1500
console.log(employee.calculateTaxes());
重写
子类可以重写其父类中定义的方法的实现,但重写的方法必须具有与原始方法相同的参数类型和相同或派生的返回类型。
class Rectangle {
area(): number {
return 0;
}
}
class Square extends Rectangle {
private side: number = 10;
area(): number {
return this.side * this.side;
}
}
let s = new Square();
// 输出100
console.log(s.area());
对象
类
其实是一种被实例化了的对象。ArkTS也可以直接以JSON格式的方式创建对象。
其中,JSON中的值可以是标量
、函数
、数组
或其他对象
。
let student = {
name: "lixingyun",
age: 20,
show: function() {
console.log(this.name + " " + this.age);
},
scores: [98, 100, 95]
}
// 输出"lixingyun 20"
student.show();
let clazz = {
name: "九年级二班",
students: student,
show: function() {
console.log(this.name + " " + this.students.name);
}
}
// 输出"九年级二班 lixingyun"
clazz.show();
接口
接口属性
接口属性可以是字段、getter
、getter或setter
和setter
组合的形式,属性字段只是getter/setter
的便捷写法。
interface Style {
color: string;
}
class StyledRectangle implements Style {
color: string = "";
}
// 将属性换成getter/setter的形式
interface Style {
get color(): string;
set color(x: string);
}
class StyledRectangle implements Style {
private _color: string = "";
get color(): string { return this._color; }
set color(x: string) { this._color = x; }
}
接口继承
就像类一样,接口也可以继承其他接口,其包含被继承接口的所有属性和方法,还可以添加自己的属性和方法。
interface Style {
color: string;
someMethod(): void;
}
interface ExtendedStyle extends Style {
width: number;
anotherMethod(): void;
}
class HtmlStyle implements ExtendedStyle {
color: string = "RED";
width: number = 0;
someMethod(): void {
console.log("someMethod()");
}
anotherMethod(): void {
console.log("anotherMethod()");
}
}
同时,一个类也可以实现多个接口。
interface I1 {
a: string;
}
interface I2 {
a: string;
}
interface I3 extends I1, I2 {
}
感谢支持
更多内容,请移步《超级个体》。