TypeScript自学笔记

news2024/12/24 9:25:13

目录

1.什么是Ts?

1.1 设计公司:微软

1.2 TS概述

1.3 TS是静态类型 JS是动态类型

1.4 TS是强类型语言 JS是弱类型语言

2.TypeScript编译器

2.1 安装

 2.2 TS自动编译和编译选项设置

3.TS的数据类型

3.1 基础数据类型number、string、boolean

3.2 Arrays(数组类型)

3.3 any(任意类型)

3.4 unknown(类型未知)

3.5 void(空值)了解

3.6 never

3.7 TS中的类型推断

3.8 Functions (函数)

3.9 Object(对象类型)

3.10 联合类型

3.11 类型别名(Type Alias)

3.12 类型语法(Interfaces)

3.13 类型断言(Type Assertion)

3.14 字面类型(Literal Types)

3.15 元组(tuple) 

3.16 枚举(Enum)

3.17 不常用类型 了解即可

3.18 类型过滤(Type Narrowing)集中数据筛选方式 感兴趣可以看下

4、TS函数

4.1函数格式:

5、class 类

5.1 类的定义

5.2 类的继承

5.3 修饰符

5.4 静态属性和方法

5.5 抽象类

5.6 多态(Polymorphism)

6.TS的接口

6.1 接口的定义

6.2 接口的用途

6.3 属性类型接口

6.4 函数类型接口

6.5 可索引性接口 了解

6.6 类类型接口

6.7接口的继承

7、TS泛型

7.1 泛型类

7.2 泛型类接口

8、TS修饰器

8.1 类装饰器 ClassDecorator(不可传参)

8.2装饰器工厂 (也可以叫柯里化,闭包,可传参)

8.3 属性装饰器

8.3 方法装饰器 MethodDecorator

8.4 各种装饰器的执行顺序


1.什么是Ts?

1.1 设计公司:微软

1.2 TS概述

官方介绍:TypeScript 是 JavaScript 的超集,这意味着它可以完成 JavaScript 所做的所有事情,而且额外附带了一些能力。
Typed JavaScript at Any Scale. 它强调了 TypeScript 的两个最重要的特性——类型系统、适用于任何规模。

(简述:JavaScript应用广泛,但是由于其为弱类型语言,使其在项目管理层面表现得相当差劲。科技巨头微软为了解决这个尴尬的问题,推出了typeScript)

1.3 TS是静态类型 JS是动态类型

静态类型:编写时要注意变量、函数的数据类型,并且在编译时就对代码类型检测并立即报错。

动态类型:编写时不需要注意变量、函数的数据类型,只有程序运行后才对代码类型检测并报错。

总体来说,静态类型语言更适合大型项目,可以减少错误并提高代码质量;而动态类型语言则更适合小型或快速开发项目,可以增加开发效率。

1.4 TS是强类型语言 JS是弱类型语言

弱类型:编程时变量可以不声明数据类型,并在赋值或运算时数据类型可以随意转换。

强类型:编程时必须明确声明数据类型,如果发现类型错误,就会在编译或运行期间发生错误。

2.TypeScript编译器

2.1 安装

tsc是TypeScript的编译器,我们一起来安装一下吧!

//安装ts编译器
npm i -g typescript

//检查是否安装成功
tsc

//ts文件编译变为js文件  (helloTS.ts这个是文件名)
tsc helloTS.ts

//ts文件编辑中  遇到无法重新声明块范围变量“*****”  (生成tsconfig.json文件就可以解决了)
tsc --init

tsc helloTS.ts 编译前

 tsc helloTS.ts 编译后

 2.2 TS自动编译和编译选项设置

2.2.1 局部-自动编译指定文件

tsc (文件名) -w  可以对指定文件自动编译

tsc helloTS1.ts -w

2.2.2 全局-自动编译文件

tsc -w

提及下tsconfig.json相关设置 (有助于自定义全局自动编译文件)

{
  // include是指定要编译哪些ts文件
 "include":[
  "./src/**/*"
 ],
//  exclude表示不包含
 "exclude":[
  "./hello/**/*"
 ],
//compilerOptions编译器的选项
"compilerOptions": {
  // target用来指定ts被编译为的Es的版本
  "target":"ES6",
  //module 指定要使用的模块化的规范
  "module": "ES6",
  //用来指定项目中要使用的库
  "lib":["es6","dom"],
  //outDir用来指定编译后文件所在的目录
  "outDir": "./dist",
  //将代码合并为一个文件
  //设置outFile后,所有的全局作用域中的代码会合并到同一个文件中
  "outFile": "./dist/app.js",
  //是否对js文件进行编译 默认是false
  "allowJs":false,
  //是否检查js代码是否符合语法规范 默认值是false
  "checkJs": false,
  //是否移除注释 默认为false
  "removeComments": false,
  //是否生成编译后的文件 
  "noEmit": false,
   //当有错误的时不生成编译后的文件 
   "noEmitOnError": false,
   //用来设置编译后的js文件是否设置严格模式
   "alwaysStrict": false,
   //不允许隐式的any类型
   "noImplicitAny": true,
  //不允许明确类型的this
  "noImplicitThis": true,
  //严格的检查空值
  "strictNullChecks": false,
},
}

3.TS的数据类型

类型例子描述
number1,-33,2.5任意数字
string“hi”,“hi”,hi任意字符串
booleantrue,false布尔值true或false
字面量其本身限制变量的值就是该字面量的值
any*任意类型
unknown*类型安全的any
void空值(undefined)没有值(或undefined)
never没有值不能是任何值
object{name:‘孙悟空’}任意的JS对象
array[1,2,3]任意JS数组
tuple[4,5]元素,TS新增类型,固定长度数组
enumenum{A,B}枚举,TS中新增类型

3.1 基础数据类型number、string、boolean

let a:number;  //数值
a = 18;
console.log(a,"number");

let b:string;  //字符串
b = 'wengzi';
console.log(b,"string");

let c:boolean;  //布尔
c = true;
console.log(c,"boolean");

3.2 Arrays(数组类型)

  • 使用数组字面量语法:可以用方括号 [] 括起来并以逗号分隔的一组值来表示一个数组。
let arr:number[];  //数组
arr=[1,2,3,4,5,6]
console.log(arr,"array");
  • 使用数组构造器:可以使用 Array 构造器来创建一个数组。
let arr1:Array<number>;  //数组
arr1=[1,2,3,4,5,6]
console.log(arr1,"array1");

3.3 any(任意类型)

any类型表示任意类型,它可以在编译时不进行类型检查和类型推断,允许我们随意地对其进行读写操作。使用any类型通常是为了处理一些动态类型、非常规类型或者无法确定类型的值。

let d: any;
d = 123;     // 赋值为数字
d = "hello"; // 赋值为字符串
d = true;    // 赋值为布尔值
console.log(d, "任意类型");

3.4 unknown(类型未知)

概念:一个安全的any,一个类型为unknown的变量,不能直接赋值给其他变量

小提示:unknown 数据类型的数据要赋值的话,得使用类型断言 详情请看->  3.13类型断言

3.5 void(空值)

void 用来表示空,用作函数的返回值类型,表示函数没有返回值。除了将void类型作为函数返回值类型外,在其他地方使用void类型是无意义的

function fn():void{
    
}

3.6 never

never类型可以作为函数的返回值类型,表示该函数无法返回一个值。

function fn2():never{
    throw new Error('报错了!!!');
    //该函数永远无法执行到末尾,返回值类型为"never"
}

3.7 TS中的类型推断

ts也可以根据赋值类型,推断出来变量的类型。

let e = "ceshi";
console.log(e, "类型推断");

3.8 Functions (函数)

function add(x: number, y: number): number {
  return x + y;
}
//调用函数
const result = add(10, 30);
console.log(result, "函数");

3.9 Object(对象类型)

  • 与js的写法类似,以下是一个简单的字面量创建对象
//使用对象字面量创建对象
const person = {
  name: "xiaoming",
  age: 18,
  gender: "female",
};
console.log(person, "对象");
  • 也可以通过接口(interface)来进行定义和约束
//定义一个person1接口
interface person1 {
  name: string;
  age: number;
  gender: string;
}

//使用接口定义对象
const person2: person1 = {
  name: "xiaohong",
  age: 20,
  gender: "female",
};
console.log(person2, "对象");

3.10 联合类型

TypeScript中的联合类型使用 | 符号将几种不同类型组合成一个新的类型。表示该变量、参数或属性可以是这些集合中任何一种类型之一

  • 定义一个联合类型变量
let numOrStr:number|string;
numOrStr=100;  //数值
numOrStr='Hello world'; //字符串
console.log(numOrStr,"联合类型");
  • 函数中的使用
function printId(id: number | string) {
  console.log("联合类型", id);
}
printId(11);
printId("文字");

小提示:

开发中会因为联合类型导致toUpperCase()方法无法使用

 解决方法如下:

(我们通过一定的条件过滤将类型做了划分,最终解决了类型交叉的问题。)

function printId(id: number | string) {
  if (typeof id === "string") {
    // In this branch, id is of type 'string'
    console.log(id.toUpperCase());
  } else {
    // Here, id is of type 'number'
    console.log(id);
  }
}

3.11 类型别名(Type Alias)

定义一个变量

type bieming = number | string;
let bm: bieming;
bm = 123;
bm = "aaa";
console.log(bm, "类型别名");

3.12 类型语法(Interfaces)

//定义一个person1接口
interface person1 {
  name: string;
  age: number;
  gender: string;
}

//使用接口定义对象
const person2: person1 = {
  name: "xiaohong",
  age: 20,
  gender: "female",
};
console.log(person2, "类型语法");

3.13 类型断言(Type Assertion)

概念:可以强制将一个值的类型转化为开发者想要的类型

  • 尖括号语法
let someValue:any="hello world"
let ceshiValue:number=(<string>someValue).length
console.log(ceshiValue,"类型断言");
  • as语法
let someValue:any="hello world"
let ceshiValue:number=(someValue as string).length
console.log(ceshiValue,"类型断言");

小提示:实际开发过程中会碰到有些类型没办法直接断言的情况,那么我们就需要断言两次,通常会使用as any或者as unknown作为第一层断言“(expr as any) as T

3.14 字面类型(Literal Types)

概念:定义一个字面类型,以后赋值只能内容 === 恒等

type myString='hello';  //定义一个字符串字面类型
type myNumber=123;      //定义一个数值字面类型
type myBoolean=true;   //定义一个布尔字面类型

let myVar1: myString = 'hello'; // 可以赋值为 'hello'
let myVar2: myString = 'world'; // 报错,只能是 'hello'

let myVar3: myNumber = 123; // 可以赋值为 123
let myVar4: myNumber = 456; // 报错,只能是 123

let myVar5: myBoolean = true; // 可以赋值为 true
let myVar6: myBoolean = false; // 报错,只能是 true

再来一个联合类型的例子

function printText(s: string, alignment: "left" | "right" | "center") {
  // ...
}
printText("Hello, world", "left");
printText("G'day, mate", "centre");

再来一个联合类型的例子

function compare(a: string, b: string): -1 | 0 | 1 {
  return a === b ? 0 : a > b ? 1 : -1;
}

3.15 元组(tuple) 

概念:元组,就是固定长度的数组,即其中的元素个数是固定的。

let h :[string,number];
h = ['a',10]

3.16 枚举(Enum)

概念:是一种常用的数据类型,用于表示固定的预定义值集合

enum Color{
    Red=1,
    Green,
    Blue,
}
console.log(Color.Red);  //输出1
console.log(Color.Green);//输出2
console.log(Color.Blue); //输出3

console.log(Color[1]);  //输出'Red'
console.log(Color[2]);  //输出'Green'
console.log(Color[3]);  //输出'Blue'

在上述代码中,我们定义了一个名为 Color 的枚举类型,并设置了三个枚举项,分别对应的数值依次为 1, 23。枚举项的名称可以通过 . 访问,也可以通过枚举值反向查找到对应的名称。

需要注意的是,如果不显式为枚举项指定数值,则它们将会从 0 开始依次递增。如果第一个枚举项指定了数值,则它之后的枚举项将在此基础上增加。

枚举是一种比较简单、直观的数据类型,可以用于表示有限的取值范围和状态等。特别是在开发过程中定义一些固定的常量时,枚举可以起到很好的作用,并提高代码的可读性和可维护性。

3.17 不常用类型 了解即可

bigint

从ES2020开始,JavaScript中有一个用于非常大整数的原语BigInt:

// Creating a bigint via the BigInt function
const oneHundred: bigint = BigInt(100);
 
// Creating a BigInt via the literal syntax
const anotherHundred: bigint = 100n;

symbol

JavaScript中有一个原语,用于通过函数Symbol()创建全局唯一引用:

const firstName = Symbol("name");
const secondName = Symbol("name");
 
if (firstName === secondName) {
This condition will always return 'false' since the types 'typeof firstName' and 'typeof secondName' have no overlap.
  // Can't ever happen
}

3.18 类型过滤(Type Narrowing)集中数据筛选方式 感兴趣可以看下

概念:使用断言、判断和匹配等手段,在特定条件下缩小一个变量的类型范围。常用的类型过滤技巧包括条件语句、类型保护函数和 in 操作符等。

  • 条件语句:
let value: string | number;
if (typeof value === 'string') {
  console.log(value.toUpperCase()); // OK,字符串类型
} else {
  console.log(value.toExponential()); // OK,数值类型
}
  • 类型保护函数:
function isPerson(obj: any): obj is Person {
  return typeof obj.name === 'string' && typeof obj.age === 'number';
}

type Person = { name: string, age: number };

function greet(person: Person | string) {
  if (isPerson(person)) {
    console.log(`Hello, ${person.name}!`); // OK,可以直接访问 person 的属性
  } else {
    console.log(`Hello, ${person}!`);
  }
}

greet({ name: "Alice", age: 25 }); // 输出:Hello, Alice!
greet("World"); // 输出:Hello, World!
  • in 操作符
type Shape = Square | Circle;

interface Square {
  width: number;
}

interface Circle {
  radius: number;
}

function area(shape: Shape) {
  if ('width' in shape) { // 判断作为 Square 类型处理
    return shape.width ** 2;
  } else { // 判断作为 Circle 类型处理
    return Math.PI * shape.radius ** 2;
  }
}

console.log(area({ width: 5 })); // 输出:25
console.log(area({ radius: 1.5 })); // 输出:7.0685834705770345

4、TS函数

4.1函数格式:

  • 格式一
function 函数名(参数列表): 返回值类型 {
    函数体 ...
    [return 返回值;]
}
  • 格式二

let 函数名 = function (参数列表): 返回值类型 {
    函数体 ...
    [return 返回值;]
};

常见写法

  • 必选参数写法

function getInfo(name:string,age:number):string{
    return `${name}---${age}`
}
console.log(getInfo('小明',1)); //正确
console.log(getInfo('小红')); //错误
console.log(getInfo(1)); //错误
  • 可选参数写法
function getInfo(name:string,age?:number):string{
    return `${name}---${age}`
}
console.log(getInfo('小明',1)); //正确
console.log(getInfo('小红')); //正确
console.log(getInfo(1)); //错误
  • 默认参数


function getInfo(name:string,age:number=20):string{
    return `${name}---${age}`
}
console.log(getInfo('小明',30)); //正确  小明---30
console.log(getInfo('小红')); //正确  小红---20
console.log(getInfo(1)); //错误
  • 剩余参数

剩余参数:在参数的类型确定而参数个数不确定的情况时,我们需要用到剩余参数,它使用 ... 将接收到的参数传到一个指定类型的数组中。

function sum(...result:number[]):number{
    let sum=0;
    for(let i=0;i<result.length;i++){
        sum+=result[i];
    }
    return sum;
}
console.log(sum(1,2,3,4,5,6));
  • 箭头函数

setTimeout(function () {
    console.log("匿名函数执行了...");
}, 1000);

setTimeout(() => {
    console.log("箭头函数执行了...");
}, 1000);

5、class 类

5.1 类的定义

class Person{
    name:string;
    constructor(n:string){  //constructor是用来定义类的构造函数
        this.name=n;
    }
    run():void{
        console.log(this.name+"在图书馆"); 
    }
}
let p=new Person('王哈哈');
p.run();

5.2 类的继承

类的继承:在TypeScript中想要实现继承使用extends关键字

class Person    {
    name: string;//父类属性,前面省略了public关键词

    constructor(n: string) {//构造函数,实例化父类的时候触发的方法
        this.name = n;//使用this关键字为当前类的name属性赋值
    }

    run(): void {//父类方法
        console.log(this.name + "在跑步");
    }
}

//中国人这个类继承了人这个类
class Chinese extends Person {
    age: number;//子类属性

    constructor(n: string, a: number) {//构造函数,实例化子类的时候触发的方法
        super(n);//使用super关键字调用父类中的构造方法
        this.age = a;//使用this关键字为当前类的age属性赋值
    }

    speak(): void {//子类方法
        super.run();//使用super关键字调用父类中的方法
        console.log(this.name + "说中文");
    }
}

var c1 = new Chinese("张三", 28);
c1.speak();

5.3 修饰符

TypeScript 里面定义属性的时候给我们提供了 三种修饰符

  • public: 默认的修饰符,可以被类的实例、子类和其他类访问。

  • private: 只能被定义它的类所访问,在其它地方无法进行访问。

  • protected: 可以被定义它的类和该类的子类所访问,但是在类外部无法访问。

class Person    {
    private name:string;  //private: 只能被定义它的类所访问,在其它地方无法进行访问。
    constructor(n: string) {
        this.name = n;
    }

    run(): void {
        console.log(this.name + "在跑步");
    }
}
class Chinese extends Person {
    age: number;

    constructor(n: string, a: number) {
        super(n);
        this.age = a;
    }

    speak(): void {
        super.run();
        console.log(this.name + "说中文");  //报错
    }
}
var c1 = new Chinese("张三", 28);
c1.speak();

5.4 静态属性和方法

static:用于声明静态成员或方法。静态成员不需要实例化即可访问。

class MathUtility {
  public static readonly PI: number = 3.14159; // 只读静态成员

  public static add(a: number, b: number): number { // 静态方法,用于求和
    return a + b;
  }
}

const sum = MathUtility.add(4, 5); // 直接通过类名调用静态方法
console.log(sum); // 输出 9
console.log(MathUtility.PI); // 直接通过类名访问只读静态变量

5.5 抽象类

抽象类是一种不能被实例化的类,因为它仍然需要子类来继承并实现其方法。抽象类中可以声明抽象方法,这些方法必须在子类中被覆盖/实现,否则子类将无法被编译通过。

//动物抽象类,所有动物都会跑(假设),但是吃的东西不一样,所以把吃的方法定义成抽象方法
abstract class Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    abstract eat(): any;//抽象方法不包含具体实现并且必须在派生类中实现
    run() {
        console.log(this.name + "会跑")
    }
}

class Dog extends Animal {
    constructor(name: string) {
        super(name);
    }
    eat(): any {//抽象类的子类必须实现抽象类里面的抽象方法
        console.log(this.name + "吃骨头");
    }
}

var d: Dog = new Dog("小狼狗");
d.eat();

class Cat extends Animal {
    constructor(name: string) {
        super(name);
    }
    eat(): any {//抽象类的子类必须实现抽象类里面的抽象方法
        console.log(this.name + "吃老鼠");
    }
}

var c: Cat = new Cat("小花猫");
c.eat();

5.6 多态(Polymorphism)

概念:指一个类的实例可以作为另一个类的实例使用。具体来说,多态允许你编写更通用、可重用和可扩展的代码,因为它支持将不同的子类对象赋值给共同的父类对象,而这些子类对象会表现出不同的行为。

class Animal {
    constructor(public name: string) {}
    makeSound() {
      console.log(` ${this.name}  会叫`);
    }
  }

  class Dog extends Animal {
    constructor() {
      super('dog');
    }
    makeSound() { // 覆盖基类方法
      console.log('汪汪!');
    }
  }
  
  class Cat extends Animal {
    constructor() {
      super('cat');
    }
    makeSound() { // 覆盖基类方法
      console.log('喵喵!');
    }
  }
  
  function animalSounds(animals: Animal[]) {
    animals.forEach(animal => {
      animal.makeSound(); // 多态调用 makeSound 方法
    });
  }
  const dog = new Dog();
  const cat = new Cat();
  const animals = [dog, cat];
  animalSounds(animals); // 输出 '汪汪!' 和 '喵喵!'

6.TS的接口

6.1 接口的定义

在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。 typescrip中的接口类似于java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等。

6.2 接口的用途

接口的用途就是对行为和动作进行规范和约束,跟抽象类有点像,但是接口中不可以有方法体,只允许有方法定义。

6.3 属性类型接口

//对传入对象的属性约束,以下这个是一个属性接口
interface FullName {
    message: string;
    num: number;
}
function printName(name: FullName) {
    console.log(name.message + "--" + name.num);
}
//传入的参数必须包含message、num
var obj = {
    age: 20,
    message: '你好',
    num: 123
};
printName(obj);//正确
// printName("1");//错误

6.4 函数类型接口

//加密的函数类型接口
interface SearchFunc {
    (source: string, subString: string): string;
  }
let m: SearchFunc = function (key: string, value: string): string {
    //模拟操作
    return key + "----" + value;
}
console.log(m("name", "王哈哈"));

6.5 可索引性接口 了解

//可索引接口,对数组的约束
interface UserArr {
    [index: number]: string
}
var arr1: UserArr = ["aaa", "bbb"];
console.log(arr1[0]);

//可索引接口,对对象的约束
interface UserObj {
    [index: string]: string
}
var arr2: UserObj = { name: '张三', age: '21' };
console.log(arr2);

6.6 类类型接口

interface Animal {
    name: string;
    eat(str: string): void;
}

class Dog implements Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    eat() {
        console.log(this.name + "吃大骨头");
    }
}

var d = new Dog("小狼狗");
d.eat();

class Cat implements Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    eat(food: string) {
        console.log(this.name + "吃" + food);
    }
}

var c = new Cat("小花猫");
c.eat("大老鼠");

6.7接口的继承

//人这个接口
interface Person {
    eat(): void;
}

//程序员接口
interface Programmer extends Person {
    code(): void;
}

//小程序接口
interface Web {
    app(): void;
}

//前端工程师
class WebProgrammer implements Person, Web {
    public name: string;
    constructor(name: string) {
        this.name = name;
    }
    eat() {
        console.log(this.name + "下班吃饭饭")
    }
    code() {
        console.log(this.name + "上班敲代码");
    }
    app() {
        console.log(this.name + "开发小程序");
    }
}

var w = new WebProgrammer("小李");
w.eat();
w.code();
w.app();

7、TS泛型

概念:泛型是一种用于编写可重复使用的代码的工具,它可以让我们在编译时期将类型作为参数传递给函数或类。通过使用泛型,我们可以编写更灵活和更通用的代码,并且可以避免类型重复定义和类型强制转换的问题。

//创建一个通用的 identity 函数
function identity<T>(arg: T): T {
    return arg;
  }
  
  let output1 = identity<string>("Hello World!");
  let output2 = identity<number>(100);

console.log(output1,"output1");
console.log(output2,"output2");

以上示例identity 函数采用一个类型参数 T,以便它可以接受任意类型的参数并返回相同的类型。在调用该函数时,我们可以使用不同的类型参数来处理不同的类型。

7.1 泛型类

泛型类可以支持不特定的数据类型,要求传入的参数和返回的参数必须一致,T表示泛型,具体什么类型是调用这个方法的时候决定的

//类的泛型
class MinClas<T>{
    public list: T[] = [];
    add(value: T): void {
        this.list.push(value);
    }
    min(): T {
        var minNum = this.list[0];
        
        for (var i = 0; i < this.list.length; i++) {
            if (minNum > this.list[i]) {
                console.log(minNum,this.list[i]);
                
                minNum = this.list[i];
            }
        }
        return minNum;
    }
}
//实例化类并且制定了类的T代表的类型是number
var m1 = new MinClas<number>();
m1.add(11);
m1.add(3);
m1.add(2);
console.log(m1.min());
//实例化类并且制定了类的T代表的类型是string
var m2 = new MinClas<string>();
m2.add('c');
m2.add('b');
m2.add('d');
console.log(m2.min());

7.2 泛型类接口

//定义操作数据库的泛型类
class MysqlDb<T>{
    add(info: T): boolean {
        console.log(info);
        return true;
    }
}

//想给User表增加数据,定义一个User类和数据库进行映射
class User {
    username: string | undefined;
    pasword: string | undefined;
}
var user = new User();
user.username = "张三";
user.pasword = "123456";
var md1 = new MysqlDb<User>();
md1.add(user);

//想给ArticleCate增加数据,定义一个ArticleCate类和数据库进行映射
class ArticleCate {
    title: string | undefined;
    desc: string | undefined;
    status: number | undefined;
    constructor(params: {
        title: string | undefined,
        desc: string | undefined,
        status?: number | undefined
    }) {
        this.title = params.title;
        this.desc = params.desc;
        this.status = params.status;
    }
}

var article = new ArticleCate({
    title: "这是标题",
    desc: "这是描述",
    status: 1
});
var md2 = new MysqlDb<ArticleCate>();
md2.add(article);

8、TS修饰器

装饰器是一种特殊类型的声明,它能够被附加到类、方法、属性或参数上,可以修改类的行为,通俗的讲装饰器就是一个方法,可以注入到类、方法、属性或参数上来扩展类、方法、属性或参数的功能。常见的装饰器有:类装饰器、方法装饰器、属性装饰器、参数装饰器。
装饰器的写法:普通装饰器(无法传参)、装饰器工厂(可传参),装饰器是过去几年中JS最大的成就之一,已是ES7的标准特性之一

首先在使用修饰器前,我们得在config.js文件中打开以下两个配置 (不打开会导致无法正常执行)

8.1 类装饰器 ClassDecorator(不可传参)

类装饰器:类装饰器在类声明之前被声明(紧靠着类声明)。类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。

//target是构造函数 ClassDecorator是值得类修饰器
const Base:ClassDecorator=(target)=>{
    //  console.log(target);
     target.prototype.haha="哈哈"
     target.prototype.fn=()=>{
        console.log("憨憨");
        
     }
}
@Base
class Http{
 //...
}
const http=new Http() as any
http.fn()
console.log(http.haha);

有的浏览器不支持  还可以这样写

//target是构造函数 ClassDecorator是值得类修饰器
const Base:ClassDecorator=(target)=>{
     target.prototype.haha="哈哈"
     target.prototype.fn=()=>{
        console.log("憨憨");
     }
}
@Base
class Http{
 //...
}
const http=new Http() as any
Base(Http) 
http.fn()

8.2装饰器工厂 (也可以叫柯里化,闭包,可传参)

//target是构造函数 ClassDecorator是值得类修饰器
const Base=(name:string)=>{
    const fn:ClassDecorator=(target)=>{
        target.prototype.haha=name
        target.prototype.fn=()=>{
           console.log("憨憨");
        }
    }
    return fn
    
}
@Base('小明')
class Http{
 //...
}
const http=new Http() as any
http.fn()
console.log(http.haha);

8.3 属性装饰器

属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2、成员的名字。

function logProperty(params:any){
    return function(target:any,attr:any){
        target[attr] = params;
    }
}

class Person {
    @logProperty('季哈哈')
    name:string | undefined;
    constructor(){

    }
    getData(){
        console.log(this.name)
    }
}

var p = new Person();
p.getData();

8.3 方法装饰器 MethodDecorator

方法装饰器
它会被应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义。
方法装饰会在运行时传入下列3个参数:
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2、成员的名字。
3、成员的属性插述符。

/**
 * 3、方法装饰器
 * 它会被应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义。
 * 方法装饰会在运行时传入下列3个参数:
 * 1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
 * 2、成员的名字。
 * 3、成员的属性插述符。
 */

//  方法装饰器  一
 function logMethods(params:any){
     return function(target:any,methodsName:any,desc:any){
         console.log(target)
         //{getData: ƒ, constructor: ƒ}
         console.log(methodsName)
         //getData
         console.log(desc)
         //{writable: true, enumerable: true, configurable: true, value: ƒ}


         //扩展属性
         target.apiUrl = 'xxx';
         target.run = function():void{
             console.log('run')
         }
     }
 }


 class Person {
    name:string | undefined;

    constructor(){

    }

    @logMethods('http://www.baidu.com')
    getData(){
        console.log(this.name)
    }
}


var p:any = new Person();
console.log(p.run());




//方法装饰器  二  修改方法
function logMethods(params:any){
    return function(target:any,methodsName:any,desc:any){
        console.log(target)
        //{getData: ƒ, constructor: ƒ}
        console.log(methodsName)
        //getData
        console.log(desc)
        //{writable: true, enumerable: true, configurable: true, value: ƒ}

        console.log(desc.value)

        //修改装饰器的方法:把装饰器方法传入的所有参数修改为string类型

        //1.保存当前的方法
        var oMethod = desc.value;

        //方法被替换了
        // desc.value = function(...args:any[]){
        //     args = args.map((item) => {
        //         return String(item)
        //     })

        //     console.log(args)
        // }

        //怎么修改当前方法呢?
        desc.value = function(...args:any[]){
            args = args.map((item) => {
                return String(item)
            })

            console.log(args)
            oMethod.apply(this.args);
        }
    }
}


class Person {
   name:string | undefined;

   constructor(){

   }

   @logMethods('http://www.baidu.com')
   getData(...args:any[]){
        console.log('我是原本的返回值')
   }
}


var p = new Person();
p.getData(123,123,123,123,1231);

8.4 各种装饰器的执行顺序

/**
 * 装饰器执行顺序
 * 结果:属性装饰器  >> 方法装饰器  >>  类装饰器
 * 同样的装饰器会先执行后面的装饰器
 */

function logClass(params:string){
    return function(target:any){
        console.log('类装饰器')
    }
}


function logAttr(params?:string){
    return function(target:any,attrName:any){
        console.log('属性装饰器')
    }
}

function logMethods(params:any){
    return function(target:any,methodsName:any,desc:any){
       console.log('方法装饰器')
    }
}



@logClass('类装饰器')
class Person {
    @logAttr('属性装饰器')
    name:string | undefined;
 
    constructor(){
 
    }
 
    @logMethods('方法装饰器')
    getData(){
         console.log('我是原本的返回值')
    }
 }



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/455179.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据架构(二)大数据发展史

1.传统数仓发展史 传统数据仓库的发展史这里不展开架构细讲&#xff0c;只需快速过一遍即可。了解这个历史发展过程即可。 1.1 传统数仓历史 1.1.1 5个时代 传统数仓发展史可以称为5个时代的经典论证战。按照两位数据仓库大师 Ralph kilmball、Bill Innmon 在数据仓库建设理念上…

吃透Redis面试八股文

Redis连环40问&#xff0c;绝对够全&#xff01; Redis是什么&#xff1f; Redis&#xff08;Remote Dictionary Server&#xff09;是一个使用 C 语言编写的&#xff0c;高性能非关系型的键值对数据库。与传统数据库不同的是&#xff0c;Redis 的数据是存在内存中的&#xf…

Python Review 01

1、Anaconda Installation 使用Anaconda Navigator进行python环境管理&#xff0c;使用conda进行依赖管理。 2、Use of Jupyter 将代码写入一个个cell&#xff0c;代码文件由一个个cell组成&#xff0c;书写代码时就像一行一行在写笔记&#xff0c;这就是notebook的代码编辑环…

无宿主机权限情况下,获取pod的日志文件

如果没有宿主机权限,是无法访问宿主机及里边的文件的,但是如果想获取某些文件,如日志等如何操作呢? 整体思路:通过抓包工具,抓取websocket的的信息,然后把信息处理拼接后导出即可。 1、启动抓包工具 我这里使用的是charles抓包工具 2、打开对应pod的命令行窗口 3、抓…

基于灰度图像和小波图的双模态卷积神经网络在心血管疾病分类中的应用

目录 一、研究对象和ECG记录预处理 二、机器学习和LSTM 三、将一维ECG记录转换为二维图像 四、双模态CNN模型 五、性能评估 参考文献 一、研究对象和ECG记录预处理 本研究采用Chapman大学和Shaoxing人民医院&#xff08;浙江大学医学院绍兴医院&#xff09;收集的12导联…

领导力专题︱如何培养与提升领导力

本文内容结构 一、领导力的核心技能 1、完美领导者&#xff1f; 2、认识你的组织需要什么 3、不同层面领导力共有的特征和技能 4、你的个人行为准则 5、领导风格 6、创造个人影响力 7、完善自己的领导网络 二、领导力与领导者 1、领导力与组织环境 2、领导者还是管理…

2023/4/23总结

项目&#xff1a; 做出了个人信息界面&#xff0c;通过点击头像的方式&#xff1a; 然后就是点击头像可以选择文件&#xff08;后面考虑是存储该文件到自己的文件夹还是只是加载该文件比较好&#xff09;只是能选择文件&#xff0c;写了指定文件后缀名的代码但是好像没什么用…

如何将Edge插件迁移至Google?

问题描述&#xff1a; 因为无法访问谷歌&#xff0c;无法从谷歌插件市场下载插件 第一步&#xff1a;在电脑上找到插件地址 高亮部分&#xff1a;自己电脑上的用户名【不同用户可能会有所不同】 C:\Users\star-dream\AppData\Local\Microsoft\Edge\User Data\Default\Extensi…

rust的现状和未来发展

rust现状: Stack Overflow 的开发者调研显示只有 7% 的开发者在使用 Rust&#xff0c;对比 JavaScript、Python 等语言&#xff0c;使用 Rust 的开发者占比并不高&#xff1b;但从 2016 年开始&#xff0c;Rust 每年都是开发者最爱的编程语言。 根据 JetBrains 2021 年的调研报…

SSH远程访问及控制

文章目录 1.SSH远程管理1.1 SSH的概述1.2 OpenSSH服务器1.3 sshd_ config常用选项设置1.4 SSH端口、配置文件 2.配置OpenSSH服务端2.1 更改端口号2.2 用户登录控制 3.登录验证方式3.1 密码验证3.2 密钥对验证3.3 配置密钥对验证 5.TCP Wrappers访问控制5.1 TCPWrappers机制的基…

第37讲:Python if-elif-else流程控制语句核心概念以及案例演示

文章目录 1.流程控制的概念2.Python中代码块的相关注意事项3.if流程控制语句的语法格式4.if流程控制的简单使用4.1.单分支的if流程控制语句4.2.加else语句的if流程控制4.3.多分支的if流程控制4.4.多分支if代码优化 5.对象的布尔值6.if-else条件表达式6.1.if-else条件表达式语法…

String的那些事儿

String作为我们最常用的Java类之一&#xff0c;在日常开发过程中充当着重要角色&#xff1f;那么大家真的了解String吗&#xff1f;让我们一起看看下面的问题&#xff1a; String内存结构&#xff1f;对象存储在堆上还是栈上&#xff1f;一个String有多长&#xff1f;占内存多…

享元设计模式解读

目录 问题引进 展示网站项目需求 传统方案解决网站展现项目 传统方案解决网站展现项目-问题分析 享元模式基本介绍 基本介绍 享元模式的原理类图 对类图的说明 内部状态和外部状态 享元模式解决网站展现项目 应用实例要求 思路分析和图解(类图) 代码实现 享元模式…

创建一个 vue 3 项目

vue create projectNameVue CLI v5.0.8 ? Please pick a preset: ❯ Default ([Vue 3] babel, eslint)Default ([Vue 2] babel, eslint)Manually select featuresbabel : ES2015 and beyond。Babel 默认使用一组 ES2015 语法转换器&#xff0c;允许你使用新的语法&#xff0c…

vue2数据响应式原理(6) 处理数组特殊遍历

打开一直在写的案例 然后 找到src下的 dataResp.js 这里 我们Observer中 数数组和对象还是要分开处理 因为他们还是有所不同 我们修改 Observer 类代码如下 class Observer{constructor(value) {//相当于 给拿到的对象 其中的__ob__绑定 值为thsi,在类中用this 表示取实例本…

数据结构入门(C语言版)一篇文章教会你手撕八大排序

八大排序 排序的概念常见的排序算法排序算法的实现一、直接插入排序二、希尔排序三、选择排序四、堆排序五、冒泡排序六、快速排序1.递归写法①三位取中函数②hoare版本③挖坑法④前后指针版本⑥快排主函数 2.非递归写法 七、归并排序1.递归写法2.非递归写法 八、非比较排序1.基…

倾斜摄影三维模型顶层合并技术及其实现方法

倾斜摄影三维模型顶层合并技术及其实现方法 倾斜摄影三维模型由于数据量大、结构复杂&#xff0c;常常需要进行顶层合并&#xff0c;以便更好地应用到城市规划、土地管理和文化遗产保护等领域。本文将介绍倾斜摄影三维模型顶层合并技术及其实现方法。 1、什么是顶层合并 倾斜…

【安全与风险】普适计算中的安全与隐私研究

普适计算中的安全与隐私研究 日常生活的数字化无处不在的计算对移动社交媒体的影响讨论更便宜的存储和更强大的处理的影响移动和普适计算的影响有时候&#xff0c;惊奇另一个例子攻击模型贡献是什么&#xff1f;智能家居的案例研究本文的主要内容如何自学? 日常生活的数字化 …

第三章 使用 Maven:命令行环境

第一节 实验一&#xff1a;根据坐标创建 Maven 工程 Maven 核心概念&#xff1a;坐标 ①数学中的坐标 使用 x、y、z 三个**『向量』作为空间的坐标系&#xff0c;可以在『空间』中唯一的定位到一个『点』**。 ②Maven中的坐标 [1]向量说明 使用三个**『向量』在『Maven的仓…

不知道今天吃什么?今天吃什么 API 告诉你

引言 在现代社会&#xff0c;由于生活节奏加快和繁忙的工作日程&#xff0c;越来越多的人感到选择今天吃什么餐点是一项繁琐且令人困扰的任务。为了解决这个问题&#xff0c;许多人会求助于在线菜谱和美食博客等渠道&#xff0c;但是这些选项通常是繁琐和耗时的。 幸运的是&a…