- 如何定义类
- "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();
- 存取器
- 在 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);
- readonly(只读属性)
class Person {
readonly name:string = 'lcc';
}
let p = new Person();
console.log(p.name); //lcc
p.name = 'ddxq' //报错(但是在编译后的js中,这样是可以的,因为ts旨在编译时起作用)
- 类里面的修饰符
/*
* 类里边的修饰符
* 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;
- 声明一个类,会得到两个类型
class Person {
name: string;
}
let p: Person = {name: "lc"} // 第一个类型,Person类的实例,是Person类型
type personType = typeof Person;
let p2: personType = Person; // 第二个是类本身的类型
7.装饰器
- 装饰器是一种特殊类型的声明,它能够被附加到类声明、方法、属性或参数上,可以修改类的行为
- 常见的装饰器有类装饰器、属性装饰器、方法装饰器和参数装饰器
- 装饰器的写法分为普通装饰器和装饰器工厂
- 类装饰器
- 类装饰器在类声明之前声明,用来监视、修改或替换类定义
- 装饰器一般来说是一个函数
// 装饰器装饰类是,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”
- 属性装饰器
- 属性装饰器表达式会在运行时当作函数被调用,传入下列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个参数对于静态成员是类的构造函数,对于实例成员是类的原型对象
- 第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("喵喵喵")
}
}
网友评论