类的定义#

class Person {
name:string;
getName():void {
console.log(this.name);
}
}
let p1 = new Person();
p1.name = 'zy'
p1.getName()

类的存取器#

  • get set 如何在ts定义使用
class User{
constructor(public myName:string) {}
get name() {
return this.myName;
}
set name(value) {
this.myName = value
}
}
let user = new User('zy');
user.name = 'z'; // 给myName赋值
console.log(user.name); // 输出赋值后的z

继承#

class Person {
name:string;
age:number;
constructor(name:string, age:number) {
this.name = name;
this.age = age;
}
getName():string {
return this.name;
}
setName(name:string):void {
this.name = name
}
}
class Student extends Person {
order:number;
constructor(name:string, age:number, order:number) {
super(name, age);
this.order = order;
}
getOrder():number {
return this.order;
}
}
const student = new Student('name', 1, 1)
// 继承的子类可以使用父类的方法,获取到父类的属性

修饰符#

1. public#

  • 公开的自己的子类和其他类都可以访问
class Father {
public name:string; // 自己的自己子类和其他类都可以访问
age:number;
constructor(name:string, age:number) {
this.name = name;
this.age = age
}
getName():string {
return this.name;
}
}
class Child extends Father {
constructor(name:string, age:number) {
super(name, age);
}
desc() {
console.log(this.name); // 子类可以访问
}
}
let child = new Child('zy', 26);
console.log(child.name); // 实例也可以访问

2. protected#

  • 受保护的自己和自己的子类可以的访问,其他类不能访问
class Father {
public name:string;
protected age:number; // 自己和自己的子类可以的访问,其他类不能访问
constructor(name:string, age:number) {
this.name = name;
this.age = age
}
getName():string {
return this.name;
}
}
class Child extends Father {
constructor(name:string, age:number) {
super(name, age);
}
desc() {
console.log(this.age); // 子类可以访问
}
}
let child = new Child('zy', 26);
// console.log(child.age); 外部访问age报错,因为是受保护的属性

3. private#

  • 私有的只有自己内部可以访问,子类和外部都不可以访问
class Father {
public name:string; // 自己的自己子类和其他类都可以访问
protected age:number; // 自己和自己的子类可以的访问,其他类不能访问
private money:number; // 只有自己可以访问
constructor(name:string, age:number, money:number) {
this.name = name;
this.age = age;
this.money = money;
}
getName():string {
return this.name;
}
}
class Child extends Father {
constructor(name:string, age:number, money:number) {
super(name, age, money);
}
desc() {
// console.log(this.money); // 子类不可以访问
}
}
let child = new Child('zy', 26, 1);
// console.log(child.money); // 外部也不可以访问

4. readonly#

  • 只读的 不能给设置了readonly的值赋值
class Person {
readonly name:string; // 只能get 不能set
constructor(name:string) {
this.name = name;
}
getName():string {
return this.name;
}
setName(v):void {
// this.name = v; // 报错因为 那么设置了readonly,所有不能赋值
}
}

5. static#

  • 静态属性,直接赋值给类,子类同样可以继承
class Person {
static age:number = 12 // 设置静态属性
name:string; // 只能get 不能set
constructor(name:string) {
this.name = name;
}
}
console.log(Person.age); // 获取类的静态属性

装饰器#

装饰类#

需要下面的配置,让ts来支持实验性的装饰器语法。

tsconfig.json
{
"experimentalDecorators": true,
}
  1. 添加属性,当前的装饰器,只能支持写死的属性。
function addName (constructor: Function) {
constructor.prototype.name = 'zy'
}
@addName
class Person {
name!:string;
constructor(){}
}
let p:Person = new Person();
console.log(p.name); // zy
  1. 添加可以传参的属性
// 用一个外层函数来接受参数
function addName (name:string) {
return function (constructor:Function) {
constructor.prototype.name = name
}
}
@addName('zy') // 动态传参
class Person {
name!:string;
constructor(){}
}
let p:Person = new Person();
console.log(p.name); // zy
  1. 装饰器函数不仅仅可以返回函数,也可以返回一个类,来替换之前的类,需要注意的是,返回新的类中的属性,只能多不能少
function replaceClass (constructor:Function) {
return class {
name!:string;
age!:number; // 属性只能多,但是不能少
constructor(){
this.name = 'zy';
this.age = 26
}
}
}
@replaceClass
class Person {
name!:string;
constructor(){}
}
let p:Person = new Person();
console.log(p.name);

装饰属性#

实例属性 装饰器参数为,当前的原型对象和属性的name

/**
* @param target 当前类的原型对象 {}
* @param key 属性的名字
*/
function toUpperCase(target:any, key:string) {
let value = target[key]; // 从原型中取出之前的属性值
/* 定义setter 和 getter方法 */
const getter = () => value;
const setter = (newVal:string) => value = newVal.toUpperCase();
if(delete target[key]) { // 如果成功删除掉了之前的属性就重新赋值
Object.defineProperty(target, key, {
set: setter,
get: getter,
enumerable: true,
configurable: true
})
}
}
class Person {
@toUpperCase // 实例属性装饰器,把属性值变成大写
name:string = 'zy';
constructor(){}
}
let p:Person = new Person();
console.log(p.name); // ZY

静态属性 装饰器参数为,当前类和属性的名字

/**
* @param target 当前类
* @param key 当前属性的名字
*/
function toAdd(target:any, key:string) {
target[key] = target[key] + 1
}
class Person {
@toAdd // 使装饰的年龄 + 1
static age:number = 26
constructor(){}
}
console.log(Person.age); // 27

装饰方法#

  1. 方法有三个参数,前两个和给属性一样,第三个是当前函数的描述属性,可以直接修改
  2. 方法和属性一样,也分静态方法和实例方法。静态方法,第一个参数是当前类。实例方法,第一个参数是当前原型
/**
* @param target 类的原型对象
* @param key 当前函数的名字
* @param descriptor 当前函数的描述符
* {
value: [Function: sum],
writable: true,
enumerable: false,
configurable: true
}
*/
function toNumber(target:any, key: string, descriptor:PropertyDescriptor) {
let oldMethod = descriptor.value;
descriptor.value = function (...arg:any[]) {
arg = arg.map(item => parseFloat(item));
return oldMethod.apply(this,arg)
}
}
class Person {
@toNumber // 把字符串参数转为数字相加
sum(...arg:any[]){
return arg.reduce((a,b) => a+b)
}
}
let p:Person = new Person();
console.log(p.sum('1','2')); // 3

装饰参数#

/**
* @param target 静态方法是当前的原型,如果实例方法就是当前类
* @param methodName 方法名字
* @param index 参数的下标
*/
function addAge(target:any, methodName:string, index:number) {
target.age = 26
}
class Person {
age!:number
toLogin(name:string, @addAge password:any) { // 装饰方法的参数
console.log(this.age);
}
}
let p:Person = new Person();
p.toLogin('zy', 123)

装饰器的执行顺序#

  1. 类装饰器最后执行,如果类有两个装饰器,靠类近的先执行,远的后执行
  2. 类装饰器里面,属性和方法,谁在上面谁先执行。
  3. 类装饰器方法,方法参数装饰器 先于 方法装饰器执行。
  4. 总结:先上后下,先内后外

抽象类#

  1. 抽象类不能被实例化
  2. 抽象方法不在父类里面实现,必须在子类中实现
// 定义一个抽象类
abstract class Animal{
name!: string;
abstract speak():void // 抽象方法,父类中不实现
}
// 子类实现
class Cat extends Animal{
speak(): void { // 必须要是想speak方法, 不然会报错
console.log('喵喵喵');
}
}
// 子类实现
class Dog extends Animal{
speak(): void {
console.log('汪汪汪');
}
}
note

词汇辨析:继承和多态

  • 继承:子类继承父类,可以获得父类的所有属性和方法。
  • 多态:同一个方法,在不同的子类中也有不同的实现。

词汇辨析:重写和重载

  • 重写:子类重写继承自父类的方法
  • 重载:函数的重载,两个或两个以上的同名函数,参数不一样,需要给同名函数提供多函数定义。