美文网首页
typescript---类

typescript---类

作者: 成熟稳重的李先生 | 来源:发表于2020-02-08 22:45 被阅读0次
  1. 如何定义类
    • "strictPropertyInitialization": true / 启用类属性初始化的严格检查/
class Person{
    name:string; // 需要将tsconfig.json中strictPropertyInitialization字段设为false,否则报错
    getName():void{
        console.log(this.name);
    }
}
let p1 = new Person();
p1.name = 'zhufeng';
p1.getName();
  1. 存取器
  • 在 TypeScript 中,我们可以通过存取器来改变一个类中属性的读取和赋值行为
  • 构造函数
    • 主要用于初始化类的成员变量属性
    • 类的对象创建时自动调用执行
    • 没有返回值
class User {
    myname:string;
    constructor(myname: string) {
        this.myname = myname;
    }
    get name() {
        return this.myname;
    }
    set name(value) {
        this.myname = value;
    }
}

let user = new User('li');
user.name = 'ccccc'; 
console.log(user.name); 
  1. readonly(只读属性)
class Person {
  readonly name:string = 'lcc';
}
let p = new Person();
console.log(p.name); //lcc
p.name = 'ddxq' //报错(但是在编译后的js中,这样是可以的,因为ts旨在编译时起作用)
  1. 类里面的修饰符
/*
* 类里边的修饰符
* public 自己,自己孩子,外人都可以访问
* protected 自己, 自己孩子能访问,外人不能访问
* private 出自己外,都不能访问
*/
class Father {
    public name: string;
    protected age: number;
    private money: number;
    condtructor(name: string, age: number, money: number) {
        this.name = name;
        this.age = age;
        this.money = money;
    }
}
// 还可以简化成这样
class Father {
    constructor(public name: string, protected age: number, private money: number) {
        this.name = name;
        this.age = age;
        this.money = money
    }
}

试着构造一个子类,来访问这些属性

class Child extends Father {
    desc() {
        console.log(this.name)  //正常
        console.log(this.age)  //正常
        console.log(this.money)  //报错: 属性“money”为私有属性,只能在类Father中访问
    }
}
let child = new Child("lc", 18, 20);
console.log(child.name)  // 正常
console.log(child.age)  // 报错: 属性“age”受保护,只能在类“Father”及其子类中访问
console.log(child.money) //报错: 属性“money”为私有属性,只能在类“Father”中访问

5.类的静态方法和静态属性

class Father {
    static className:string = "Father";
    static getClsName() {
        return Father.className;
    }
}
class Child extends Father {
}
console.log(Child.className, Child.getClsName())//Father, Father
//原理是
Object.setPrototypeOf(Child, Father)//即 Child.__proto__ = Father;
  1. 声明一个类,会得到两个类型
class Person {
    name: string;
}
let p: Person = {name: "lc"}  // 第一个类型,Person类的实例,是Person类型
type personType = typeof Person;
let p2: personType = Person; // 第二个是类本身的类型

7.装饰器

  • 装饰器是一种特殊类型的声明,它能够被附加到类声明、方法、属性或参数上,可以修改类的行为
  • 常见的装饰器有类装饰器、属性装饰器、方法装饰器和参数装饰器
  • 装饰器的写法分为普通装饰器和装饰器工厂
  1. 类装饰器
  • 类装饰器在类声明之前声明,用来监视、修改或替换类定义
  • 装饰器一般来说是一个函数
// 装饰器装饰类是,target指要装饰的类
function enhancer(target: any){ 
    target.prototype.name = 'lcc';
    target.prototype.getName = function(){
        return this.name;
    }
}
@enhancer
class Person {
}
let p = new Person();
console.log(p.name); //这里报错,p是Person类,但Person上没有name属性
console.log(p.getName())  // 这里报错,理由同上
//但是,在编译后的js中,以上代码正常运行,也能得到正常结果。TS不识别装饰器
//可以优化成这样
console.log((p as any).name);  //这样,就不会报错了
  • 替换类定义
function connect(target: any){
    return class {
        name: string = "abc"
    }
}
@connect
class App{
}
let app = new App();
console.log((app as any).name)  //“abc”
  1. 属性装饰器
  • 属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数
  • 属性装饰器用来装饰属性
    • 第一个参数对于静态成员来说是类的构造函数,对于实例成员是类的 原型对象
    • 第二个参数是属性的名称
  • 方法装饰器用来装饰方法
    • 第一个参数对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
    • 第二个参数是方法的名称
    • 第三个参数是方法描述符
//此处,target为类的原型对象(Person.prototype), propertyKey是属性名
function upperCase(target: any, propertyKey: string) {  
    let value = target[propertyKey];
    const getter = function() {
        return value;
    }
    const setter = function(newVal:string) {
        value = newVal.toUpperCase();
    }
    if(delete target[propertyKey]) {
        Object.defineProperty(target, propertyKey, {  //虽然此处将属性定义在了原型上,但是在实例化的过程中,它也会监听到实例的属性
            get: getter,
            set: setter,
            enumerable: true,
            configurable: true
        })
    }
}
class Person {
    @upperCase
    name: string = "lcc";
}
console.log(new Person().name) // LCC
// 方法装饰器
function convertNumber(target: any, methodName: string, descriptor: PropertyDescriptor) {
    let oldMethod = descriptor.value;
    descriptor.value = function(...args:any[]){
        args = args.map(item => parseInt(item));
        return oldMethod.apply(this, args);
    }
}
class Demo {
    @convertNumber  // 这个装饰器的作用是将非数字转化为数字
    sum(...args:Array<any>){
        return args.reduce((a, b) => a+ b, 0)
    }
}
  1. 参数装饰器
  • 会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元数据
    • 第1个参数对于静态成员是类的构造函数,对于实例成员是类的原型对象
    • 第2个参数的名称
    • 第3个参数在函数列表中的索引
/*
 *此处addAge所对应的是实例原型的方法,因此
 *1.target对应的是原型对象
 *2.methodName即要修饰的参数所在的方法名、
 *3.paramIndex是要修饰的参数在方法中的索引
 */
interface Person {
    age: number
}

function addAge(target:any, methodName: string, paramIndex: number) {
    console.log(arguments);
    target.age = "liccc"
}
class Person {
    login(username: string, @addAge password: number){
        console.log(this.age, username, password)
    }
}
let p = new Person();
p.login("dxq", 123456)

11.装饰器执行顺序

  • 有多个参数装饰器时:从最后一个参数依次向前执行
  • 方法和方法参数中参数装饰器先执行。
  • 类装饰器总是最后执行
  • 方法和属性装饰器,谁在前面谁先执行。因为参数属于方法一部分,所以参数会一直紧紧挨着方法执行
function Class1Decorator() {
        return function (target: any) {
            console.log("类1装饰器");
        }
    }
    function Class2Decorator() {
        return function (target: any) {
            console.log("类2装饰器");
        }
    }
    function MethodDecorator() {
        return function (target: any, methodName: string, descriptor: PropertyDescriptor) {
            console.log("方法装饰器");
        }
    }
    function Param1Decorator() {
        return function (target: any, methodName: string, paramIndex: number) {
            console.log("参数1装饰器");
        }
    }
    function Param2Decorator() {
        return function (target: any, methodName: string, paramIndex: number) {
            console.log("参数2装饰器");
        }
    }
    function PropertyDecorator(name: string) {
        return function (target: any, propertyName: string) {
            console.log(name + "属性装饰器");
        }
    }

    @Class1Decorator()
    @Class2Decorator()
    class Person {
        @PropertyDecorator('name')
        name: string = 'zhufeng';
        @PropertyDecorator('age')
        age: number = 10;
        @MethodDecorator()
        greet(@Param1Decorator() p1: string, @Param2Decorator() p2: string) { }
    }
}
/**
name属性装饰器
age属性装饰器
参数2装饰器
参数1装饰器
方法装饰器
类2装饰器
类1装饰器
 */

12.抽象类

  • 抽象描述一种抽象的概念,无法被实例化,只能被继承
  • 无法创建抽象类的实例
  • 抽象方法不能在抽象类中实现,只能在抽象类的具体子类中实现,而且必须实现 (用意是防止使用者忘记声明)
abstract class Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    getName() {
        return this.name;
    }
    abstract speak(): void;
 }
class Cat extends Animal {
    speak(): void {
        console.log("喵喵喵")
    }
}

相关文章

  • typescript---类

    如何定义类"strictPropertyInitialization": true / 启用类属性初始化的严格检查...

  • TypeScript---类

    TS(集成可选类型批注)支持ES6。 接下来我们创建一个类文件class.ts。 Shape 类中有两个属性 ar...

  • typescript---函数

    函数的定义 可以指定参数的类型和返回值的类型 2.函数表达式 定义函数类型通过关键字type来定义函数类型 可选参...

  • typescript---接口

    1.接口一方面可以在面向对象编程中表示为行为的抽象,另外可以用来描述对象的形状;2.接口就是把一些类中共有的属性和...

  • TypeScript---继承

    继承一个已存在的类并创建一个派生类。继承使用关键字extends。 派生类Shape3D: 1,派生类Shape3...

  • TypeScript---类型批注

    TS通过类型批注提供静态类型,方便在编译时启动类型检查,这不是必须的,甚至可以被忽略,去使用js常规的动态类型。...

  • typescript---泛型

    泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性泛...

  • typescript---结构类型系统

    接口的兼容性 如果传入的变量和声明的类型不匹配,TS就会进行兼容性检查 原理是Duck-Check(一个对象,只要...

  • TypeScript---箭头函数表达式(lambda表达式)

    lambda表达式()=>{something}或()=>something相当于js中的函数,它的好处是可以自动...

  • Character类、Math类、Random类、System类

    Character类 首先我们来了解它的概述及其构造方法 Character类概述Character 类在对象中包...

网友评论

      本文标题:typescript---类

      本文链接:https://www.haomeiwen.com/subject/dlyexhtx.html