demo:ts:class基本使用和本质
class Greeter {
// 1. 基本使用:成员变量/构造函数/成员函数(原型方法)
greeting: string;
constructor(message: string){ this.greeting = message; };
sayHi() { console.log(this.greeting); }
}
let myGreeter1 = new Greeter('你好');
myGreeter1.sayHi(); // hi, nice to meet you!
// 2. class本质是function
console.log(`type of Greeter: `, typeof Greeter) // type of Greeter: function
console.log(`type of myGreeter1: `, typeof myGreeter1) // type of myGreeter1: object
demo:ts:public protected private
修饰器+属性或方法,可以限制访问
- public,TypeScript里,成员(包括属性和方法)都默认为 public
- private,只能当前类内部访问, 子类和实例不能访问
- protected,可在当前类和子类内部访问, 实例不能直接访问
修饰+构造函数
- private ,该类不允许被继承或者实例化
- protected,该类运行被继承,不允许实例化
class Plant {
public name:string; // public 子类和实例都可访问
protected age: number; // protected 子类可访问,实例不可访问
private region: string; // private:子类和实例都不可访问
// protected修饰构造函数,意味着Plant不能被实例化
protected constructor(name:string, age: number, region:string){
this.name = name;
this.age = age;
this.region = region;
}
};
class Bamboo extends Plant {
public color: string;
// public修饰构造函数,意味着Bamboo可以被实例化
public constructor(name: string, age:number, region:string, color: string){
super(name, age, region);
this.color = color;
}
// 1. 继承的属性访问限制
public getInfo(){
console.log(`my name is ${this.name}`); // public 子类可访问
console.log(`my age is ${this.age}`); // protected 子类可访问
console.log(`my region is ${this.region}`); // compile error! private 子类不可访问
}
};
// 2. 实例化的构造函数访问限制
let plant1 = new Plant('tree', 2, 'south'); // compile error! Plant不可实例化
let bamboo1 = new Bamboo('boom1', 1, 'north','lightGreen'); // Bamboo可实例化
// 3. 实例对象的属性访问限制
// 不可以访问bamboo1.age和bamboo1.region
console.log(`bamboo1.name=${bamboo1.name}, bamboo1.color=${bamboo1.color}`); // OK
demo:ts:readonly
readonly
- 修饰成员属性
- 声明时和构造时,可写
- 实例化对象时,不可泄
class Octopus {
// readonly变量声明时初始化可写
public readonly enviroment: string; // 只读
public readonly legs: number = 8; // 只读
public name: string;
// readonly变量构造函数时初始化可写
public constructor(enviroment: string, name: string, legs: number) {
this.enviroment = enviroment;
this.legs = legs;
this.name = name;
}
}
// 运行
let oct1 = new Octopus('海洋', '1号章鱼', 9);
oct1.name = '1号巨型章鱼' // ✅
oct1.enviroment = '深海' // ts编译❌ Cannot assign to 'enviroment' because it is a read-only property.
oct1.legs = 10 // ts编译❌ Cannot assign to 'legs' because it is a read-only property.ts(2540)
demo:ts:构造函数
// 1. 构造函数普通方式
class OriginalAnimal{
private name:string;
public constructor(name: string){
this.name = name;
}
getInfo(){console.log(`OriginalAnimal: name=${this.name}`);}
}
let myOrigin1 = new OriginalAnimal('kawa1');
myOrigin1.getInfo(); // OriginalAnimal: name=kawa
// 2. 构造函数语法糖模式
class OriginalAnimal{
// 修饰词默认是public,ts中此构造函数和上面的OriginalAnimal构造函数是等价的
// 一条语句完成: 成员属性定义和构造函数定义
constructor(private name:string){};
getInfo(){console.log(`OriginalAnimal: name=${this.name}`);}
}
let myOrigin1 = new OriginalAnimal('kawa2');
myOrigin1.getInfo(); // OriginalAnimal: name=kawa2
demo:ts:静态属性
静态属性
- static关键字声明
- 属于类,不属于实例
- 可以通过类名.静态属性来访问
class Movie{
public static goal:string = '科幻'; // 静态属性
public constructor(public name:string) { };
public getInfo(){console.log(`name=${this.name} goal=${Movie.goal}`);}
};
// 运行
let myMovie = new Movie('黑客帝国');
// 类内部访问静态属性 ✅
myMovie.getInfo(); // name=黑客帝国 goal=科幻
// 类外部访问静态属性 ✅
console.log(Movie.goal); // 科幻
demo:ts:私有属性语法糖
class Person {
// 公有属性 name 私有属性: age/weight
name; #age; #weight;
constructor(name: string, age: number, weight: string) {
this.name = name;
this.#age = age;
this.#weight = weight;
}
intro() {
console.log('age=', this.#age)
console.log('weight=', this.#weight)
}
}
// 运行:
// 1. 配置选项("target": "ES2015")
// 2. 运行命令(tsc --build tsconfig.json && node script.js)
let p = new Person('小丽', 18, '45kg')
// 公有属性可以直接访问
console.log('name=', p.name) // name=小丽
// 私有属性可以通过方法访问
p.intro() // age= 18 weight= 45kg
// 私有属性不可以直接访问,编译报错
// error: Property '#age' is not accessible outside class 'Person' because it has a private identifier.
// console.log('age=', p.#age)
// console.log('weight=', p.#weight)
demo:class原型链
class Cpoint {
constructor(x,y){
console.log('@Cpoint 构造函数...',x,y);
this.x = x;
this.y = y;
}
}
let p1 = new Cpoint(1,2); // test
console.log(Cpoint.prototype.__proto__ === Object.prototype); // true
// 不带继承的原型链关系
// - 原型链关系 可以把Point看成是function
// 父类
class Point {
constructor(x,y){
this.x = x;
this.y = y;
}
}
// 子类
class Cpoint extends Point{
constructor(x,y,color){
super(x,y);
this.color = color;
}
}
let cp1 = new Cpoint(100,50,'red');
console.log("cp1: ", cp1); // cp1 {x:100,y:50,color:'red'}
console.log('原型链:', cp1.__proto__ === Cpoint.prototype); // true
console.log('原型链:', Cpoint.prototype.__proto__ === Point.prototype); // true
console.log('原型链:', Point.prototype.__proto__ === Object.prototype); // true
// 有继承的原型链关系
// - 可以把CPoint和Point看成是function
// - 两个class的关系可以看成是es5中类似寄生组合关系
总结
class本质
- 本质: 依然是function,class语法让对象原型更清晰、更面向对象编程
- 作用: 代码复用,比如继承,实例化
构造方法
- 作用: 初始化实例,构造方法可被子类继承
- 父类
constructor() { return this }
- 子类
constructor(...args) { super(...args);}
原型方法
- class内部成员方法
- 相当于es5语法中prototype方法
- 原型方法是所有实例对象所共享和继承的,public修饰词
静态方法
- static关键字 + class内方法
- 静态方法属于类,可被class名调用,无法访问实例的this(undefined)
- 静态方法可与原型方法重名
- 父类的静态方法,可以被子类继承