TypeScript,从0到入门带你进入类型的世界

ts vs js

从0到入门进入TS的世界

  • 一、什么是TypeScript?
    • 1、编程语言的类型
    • 2、TypeScript究竟是什么?
  • 二、为什么要学习TypeScript?
    • 1、程序更容易理解
    • 2、效率更高
    • 3、更少的错误
    • 4、非常好的包容性
    • 5、一点小缺点
  • 三、typescript入门
    • 1、如何安装TypeScript
    • 2、查看版本号
  • 四、Typescript数据类型
    • 1、原始数据类型和Any类型
      • (1)原始数据类型
      • (2)Any 类型
    • 2、数组和元组
      • (1)数组
      • (2)元组
    • 3、interface 接口
    • 4、function函数
    • 5、类型推论、联合类型和类型断言
      • (1)类型推论
      • (2)联合类型
      • (3)类型断言
  • 五、Typescript中的类:class
    • 1、类的定义
      • (1)类(Class)
      • (2)对象(Object)
      • (3)面向对象(OOP)的三大特性
    • 2、Typescript中的类
    • 3、类和接口
      • (1)解决什么问题
      • (2)如何解决
      • (3)举个例子
  • 六、枚举
    • 1、普通枚举
    • 2、常量枚举
  • 七、泛型
    • 1、普通泛型
    • 2、约束泛型
    • 3、泛型在类和接口中的使用
      • (1)泛型在类中的使用
      • (2)泛型在接口中的使用
  • 八、类型别名
    • 1、类型别名
    • 2、字符串字面量
    • 3、交叉类型
  • 九、声明文件
    • 1、 .d.ts 文件引入
    • 2、npm安装
  • 十、内置类型
  • 十一、结束语

众所周知, js 是一门弱类型语言,并且规范较少。这就很容易导致在项目上线之前我们很难发现到它的错误,等到项目一上线,浑然不觉地, bug 就UpUp了。于是,在过去的这两年, ts 悄悄的崛起了。

周一随着一波热潮,也开始进入了 ts 的世界,不得不感叹 ts 的静态美。

下面的文章中将讲解我对 TS 入门的一些归纳总结。一起来了解一下吧!

一、什么是TypeScript?

1、编程语言的类型

动态类型语言(Dynamic Typed Language)静态类型语言(Statically Typed Langeage)
JavaScriptC,C++,C#,JAVA

2、TypeScript究竟是什么?

  • Typescript,即 Javascript that scales ;

  • ts 把不看重类型的动态语言 JS 转变成关注类型的静态语言;

  • 可以说ts是静态类型风格的类型系统;

  • 从 es6 到 es10 甚至是 esnext 的语法支持;

  • 兼容各种浏览器,各种系统,各种服务器,完全开源。

二、为什么要学习TypeScript?

1、程序更容易理解

动态语言存在函数或者方法中其输入输出的参数类型等问题,同时,动态语言还受到各种各样的约束,比如需要手动调试等等。那么有了 ts ,代码本身就可以解决上述问题了, ts 让程序更容易理解,程序理解我们,我们就可以少干很很多事情。

就像我们在与别人交谈时,假如我们逻辑很清晰的表达给对方,对方马上听懂了,并且理解了我们,我们也很省力,不用长篇大论的介绍。

2、效率更高

ts 可以在在不同的代码块和定义中进行跳转,并且代码有补全功能。

同时, ts 还有丰富的接口提示,可以通过使用 . 来提示所有的接口内容。

3、更少的错误

ts 在编程期间,就可以发现大部分的错误。这样就可以杜绝掉一些比较常见的错误,也使得后面程序运行更加通畅。

4、非常好的包容性

ts 可以完全地兼容 Javascript ,同时,如果要引入像 JQuery 之类的第三方库时,可以单独编写类型文件来引入这些库。

5、一点小缺点

相比于 js 来讲, ts 在学习之初,需要去习惯一些规范,短期内会增加一点学习成本。但短期的学习成本增加将会使得在后期的开发当中减少很多不必要的错误和麻烦,间接的也为自己的开发带来很大的益处。

闲谈到此结束,让我们一起来进入 ts 的世界吧!

三、typescript入门

1、如何安装TypeScript

npm install -g typescript 

2、查看版本号

tsc -v

四、Typescript数据类型

1、原始数据类型和Any类型

(1)原始数据类型

//定义一个布尔值数据
let isDone: boolean = false//定义一个数字类型
let age: number = 20//定义字符串类型
let firstName: string = 'monday'
let message: string = `Hello, ${firstName}`//定义undefind和null类型
let u: undefined = undefined
let n: null = null//给数字赋值undefid
let num: number = undefined

(2)Any 类型

如果我们有时候不能确定一个数据是什么类型的话,那么我们可以用any类型来定义。比如:

//定义一个any类型数据
let notSure: any = 4
notSure = 'maybe a string'
notSure = truenotSure.myName
notSure.getName()

2、数组和元组

(1)数组

//声明一个数字类型的数组
//注意:后面的数组只能传递数字,传递其他类型的数据都会报错
let arrOfNumbers: number[] = [1, 2, 3];
arrOfNumbers.push(3)function test(){//arguments 为类数组console.log(arguments)
}

(2)元组

//确定一个元组里面的内容和数量,下面表示确定user这个元组必须且只能接收两个参数
//同时第一个属性必须是String类型,第二个属性是Number类型
let user: [String, Number] = ['abc', 13]

3、interface 接口

interface的定义:

  • 对 对象Object 的形状 (shape) 进行描述;
  • Duck Typing(鸭子类型)。

我们来看一段代码:

interface Person{// readonly表示只读状态readonly id: number,name: String,//加一个问号表示该参数可选可不选age?: number
}let monday: Person = {id: 1,name: 'monday',age: 18
}monday.id = 12323; //因为加了readonly,所以此时访问不了,会报错

4、function函数

function函数是什么:

  • 在 JS 中,函数是一等公民。
  • 函数和其他类型的对象都一样,可以作为参数,可以存入数组,也可以被另外一个函数返回,可以被赋值给另外一个变量。
  • 函数主要由两个部分组成:输入(传参)和输出(返回结果)。

我们来看个例子:

function add(x: number, y: number, z?: number): number{if(typeof z === 'number'){return x + y + z;}else{return x + y;}
}let result = add(1, 2, 3);
console.log(result); //6

通过以上函数,我们实现了两个树或者三个树的相加操作。此时,需要我们注意的是,可选参数后面不能再添加不确定参数,否则程序就会发生混乱。比如:

function add(x: number, y: number, z?: number, t: number): number{if(typeof z === 'number'){return x + y + z;}else{return x + y;}
}

以上代码中的 t 是肯定不被允许添加的,因为前面已经有了可选参数 z ,而后面又突然健冒出来个 t ,想想都不太合理。


到这里,假设我们由一个新的变量名,名字叫 add2 。这个时候我们想要给它像 add 函数一样的类型。那么该怎么处理呢?

let add2: (x:number, y:number, z?: number) => number = add

注意上面这个箭头 => 不是 ES6 中的箭头函数,而是 ts 中声明函数类型返回值的方法。

上面这个语句中就说明了, add2 返回的值是一个 number 类型数值,并且让它等于 add 函数。同时,要记得的是,在 ts 当中,凡是在 : 后面都是声明在声明类型。


上面这样写好像有点冗余,我们来用 interface 来实现同样的效果。

在第3点的 interface 中我们了解到, interface 是对对象的形状进行描述,但值得注意的是, interface 也可以是对函数的形状进行描述。我们用代码来实现一下。

interface ISum {(x: number, y: number, z?: number) : number
}let add2: ISum = add

通过以上代码,我们看到,用 interface 来封装一个函数的返回值来行,看起来优雅了不少。这里先体会一下, interface 的强大之处,在后面还会继续讲解。

5、类型推论、联合类型和类型断言

(1)类型推论

有时候我们还没有给一个数据定义类型,就直接给它赋值了。这个时候我们要怎么来判断呢。这个数据的类型呢?

比如:

let str = 123

当出现这样的情况时,编译器会直接给 str 赋上 number 类型。那么此时如果我们想这么干:

let str = 123
str = 'asd' //会报错

结果当然时不行的。当第一次赋值的时候,编译器就已经给 str 一个 number 类型,认定 str 就是 number 类型。而后我们还想要给 str 赋值上一个 string 类型的数据,肯定是会报错的。

(2)联合类型

有时候我们对一个数据的类型不够确定,比如说不知道某一个数据它是 number 类型还是 string 类型。这个时候我们就可以用联合类型来进行一波操作。

let numberOrString: number | string

通过这种方式,我们对我们所定义的属性 numberOrString 进行联合类型操作。

一般情况下,联合类型会结合类型断言来进行使用。接下来我们来讲类型断言。

(3)类型断言

1) 当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型中共有的属性或方法,而有时候呢,我们确实需要在还不确定类型的时候就访问其中一个类型特有的属性或方法。因此我们采用类型断言的方式将其指定为一个类型。(这么做只是先欺骗了 ts ,让其信任我们所指定的类型)

let str = 123
function getLength(input: string | number) : number{// 用as对input进行类型断言,先给input指定一个类型,后面判断不是再进行转换//注意:类型断言只做类型选择,而不做类型转换const str = input as stringconsole.log(typeof str)if(str.length){return str.length}else{const number = input as numberreturn number.toString().length}
}

2) 看到这里,已经开始感觉到类型断言的神奇之处。但用上面这种方法感觉好像还有一点点冗余,于是我们引入一个 type guard ,即类型守护。我们来看下实现方式。

let str = 123
function getLength2(input: string | number): number{if(typeof input === 'string'){return input.length}else{return input.toString().length}
}

五、Typescript中的类:class

在 js 中我们用了构造函数和原型链的方式来实现继承,同时在 ES6 中出现了 class 类继承的方法。那在 typescript 中呢,继承的方法又更加丰富了。让我们一起来一探究竟吧!

1、类的定义

我们先来看下类的定义。

(1)类(Class)

类定义了一切事物的抽象特点,包含它的属性和方法。比如:

class Animal{// 构造函数是实例化执行时候的逻辑constructor(name){this.name = name}run(){return `${this.name} is running`}
}

阅读以上代码我们可以知道,通过 class 可以定义一个类。

(2)对象(Object)

对象 Object ,就是类的实例。举个例子: 🙆‍♂️

我们可以把类 class 比喻成一张蓝图,比如说汽车是一个 class ,那么它就像是一张造汽车的图纸。第二个是 Object, Object 通过 new 生成,那么前面有了汽车的蓝图,我们现在就可以创造实实在在的汽车了。我们可以说一辆特斯拉是汽车的实例,也可以说宝马是汽车的另外一个实例。

同样我们用上面的例子来做衍生。具体如下:

class Animal{// 构造函数是实例化执行时候的逻辑constructor(name){this.name = name}run(){return `${this.name} is running`}
}
const snake = new Animal('lily')
console.log(snake.run())

阅读以上代码我们可以知道,我们定义了一个 snake ,这个 snake 继承了 Animal 类,因此它就可以用 Animal 类的属性和方法。

此时打印结果如下:

实例

(3)面向对象(OOP)的三大特性

面向对象的三大特性分别为:封装、继承、多态 。

  • 封装: 指将数据的操作细节隐藏起来,只暴露对外的接口。那这样子的话,对于外界的调用端来说,他们不需要也不可能知道细节,只能通过对外的接口来访问该对象。
  • 继承: 子类可以继承父类,子类除了拥有父类的所有特征外,还会拥有一些更具体的特性。
  • 多态: 由继承产生的相关不同的类,对同一个方法可以有不同的响应。比如,猫和狗,他们都可以继承 Animal 类,但是他们分别实现 run() 方法,此时呢,针对某一个实例,我们无需了解它是猫还是狗,这个时候可以直接调用 run() ,程序会自动判断出来,应该如何去执行这个方法。

同样,我们用上面的代码做衍生,来看继承和多态是怎么样的。


继承:

class Animal{// 构造函数是实例化执行时候的逻辑constructor(name){this.name = name}run(){return `${this.name} is running`}
}
const snake = new Animal('lily')
// console.log(snake.run())class Dog extends Animal{bark(){return `${this.name} is barking`}
}const xiaoqi = new Dog('xiaoqi')
console.log(xiaoqi.run())
console.log(xiaoqi.bark())

此时打印结果如下:

继承

从上面可以看到, Dog 继承了 Animal 类,此时 Dog 就拥有了 Animal 类的属性和方法。而 xiaoqi 实例化了 Dog ,因此它也拥有 Dog 的属性和方法。


多态:

class Animal{// 构造函数是实例化执行时候的逻辑constructor(name){this.name = name}run(){return `${this.name} is running`}
}
const snake = new Animal('lily')
// console.log(snake.run())
//-----------------------------------
class Dog extends Animal{bark(){return `${this.name} is barking`}
}const xiaoqi = new Dog('xiaoqi')
console.log(xiaoqi.run())
console.log(xiaoqi.bark())
//-----------------------------------
class Cat extends Animal{// 静态方法不需要进行实例化,直接在类上调用即可static categories = ['mammal']constructor(name){super(name)console.log(this.name)}run(){return `Meow, ` + super.run() }
}
const maomao = new Cat('maomao')
console.log(maomao.run())
// 直接访问静态属性
// 为什么要有静态属性?当定义和实例没有太大关系时,可以考虑使用静态方法实现
console.log(Cat.categories)

此时打印结果如下:

多态

阅读代码我们可以发现, xiaoqi 继承了 dog 的 run() 方法,而 Cat 继承了 Animal 类,但是它对 run() 方法进行了改写,因此最终的 run() 方法为改写后的效果。

所以, maomao 继承了 Cat 类,最后 maomao 调用 run() 方法时,就会调用 Cat 里面改写的 run() 方法,而不是 Animal 类的 run() 方法。

这样, xiaoqi 和 maomao 虽然同样继承自 Animal 类,但他们调用 run() 方法的结果各自相互独立,如此,就实现了多态。

同时,我们还要注意一个点,就是静态属性。大家可以看到上面定义的 categories ,用了 static 来定义它为静态属性。当把变量定义为静态属性时,则当外部需要该静态方法时,不需要进行实例化,之类在类上调用即可。

那么问题来了,我们什么时候才需要有静态属性呢?

其实,当定义的内容和实例没有太大关系时,就可以考虑使用静态方法。比如常量的使用,常量基本是固定的,不会变的,所以我们可以考虑直接使用静态方法来获取它。

2、Typescript中的类

Typescript是通过什么方式来增强类的呢,typescript一般通过以下四种修饰符来增强类:

修饰符含义
public修饰的属性或方法是公有的
private修饰的属性或方法是私有的
protected修饰的属性或方法是受保护的
readonly只能读不能写

有了以上这四种修饰符呢,我们就可以给类的方法和属性进行权限管理。为什么要做权限管理呢?因为总有些内容,我们是不愿意暴露给外部使用的,所以需要进行权限管理。

值得注意的是,对于 protected 这个修饰符来说,只有子类可以访问父类的属性和方法,其他实例都不能访问。这其实可以把 protected 这个变量理解为遗产,父类的东西直接给子女继承,其余外部人员一概不能访问。

3、类和接口

(1)解决什么问题

继承存在着这样一个困境,在面向对象的世界中,一个类只能继承另外一个类,有时候同类之间有一些共同的特性,但是使用子类来继承父类又很难完成。于是接口就出现了。

(2)如何解决

类可以使用 implements 来实现接口,怎么做呢?我们可以把这些相同的特性提取成接口,然后用 implements 这个关键字来实现,这样就大大提高了面向对象的灵活性。

(3)举个例子

假如我们现在要让一辆汽车和一部手机来实现打开播放器的功能,那么我们会这么实现:

class Car{switchRadio(trigger: boolean){}
}class CellPhone{switchRadio(trigger: boolean){}
}

但是这样子看起来好像就没有特别雅观。于是我们可以写一个打开播放器的接口,然后用 implements 来实现这个功能。代码如下:

interface Radio{switchRadio(trigger: boolean): void
}class Car implements Radio{switchRadio(trigger: boolean){}
}class CellPhone implements Radio{switchRadio(trigger: boolean){}
}

这样,就让Car和CellPhone实现了打开播放器的功能。

接下来,我们继续写一个接口,可以实现检查电池电量的功能。并且让手机不仅可以打开播放器,还可以检查电池电量。代码如下:

interface Radio{switchRadio(trigger: boolean): void
}interface Battery{checkBatteryStatus(): void
}class Car implements Radio{switchRadio(trigger: boolean){}
}class CellPhone implements Radio,Battery{switchRadio(trigger: boolean){}checkBatteryStatus(){}
}

阅读代码我们可以发现,我们要给继承两个接口 Radio,Battery ,这样看似乎还有点冗余。于是我们可以这样实现:

interface Radio{switchRadio(trigger: boolean): void
}interface RadioWithBattery extends Radio{checkBatteryStatus(): void
}class Car implements Radio{switchRadio(trigger: boolean){}
}class CellPhone implements RadioWithBattery{switchRadio(trigger: boolean){}checkBatteryStatus(){}
}

通过 interface 继承 interface ,最终用 implement 去抽象和验证类的属性和方法,达到抽离功能的目的。

相信通过以上的简单了解,大家能感受到一点 interface 的奇妙之处。

六、枚举

1、普通枚举

枚举常使用于我们在程序中需要做权限管理或者做判断时等各种场景。枚举比较简单,下面直接用代码演示:

enum Direction{Up,Down,Left,Right
}console.log(Direction.Up) //0
console.log(Direction.Down) //1
console.log(Direction.Left) //2
console.log(Direction.Right) //3
console.log(Direction[0]) //Up

除了以上基本用法外,我们还可以给枚举赋值:

enum Direction{Up = 10,Down,Left,Right
}console.log(Direction.Up) //10

2、常量枚举

我们来定义一个常量,与 enum 做判断。

enum Direction{Up = 'Up',Down = 'Down',Left = 'Left',Right = 'Right'
}//定义一个常量,直接与enum做判断
const value = 'Up';
if(value === Direction.Up){console.log('go Up!') // go Up!
}

使用常量枚举可以有效地提升性能,常量会内联枚举的任何用法,而不会把枚举变成任意的 Javascript 代码。

这样一说,那是不是所有的 enum 都可以使用常量枚举呢?答案自然是否定的。

枚举的值有两种类型,一种是常量值枚举(constant),一种是计算值枚举(computed)。只有常量值枚举可以进行常量枚举,而计算值枚举不能进行常量枚举。

七、泛型

接下来我们来讲 TypeScript 中最难的一部分,泛型。

1、普通泛型

泛型,即 generics 。指在定义函数、接口或类的时候,我们不预先指定类型,而是在使用的时候再指定类型和其特征。

可以理解为,泛型就相当于一个占位符或者是一个变量,在使用时再动态的填入进去,填进去以后既可以来确定我们的类型值。

接下来我们用代码来演示一下:

function echo<T>(arg: T): T{return arg
}const result = echo(true)
console.log(result) // true

我们通过 <> 来定义一个未知的泛型,之后当我们给它赋值时,就可以对应值的数据类型。


现在我们再用泛型来定义一个 number 类型的数组。具体代码如下:

// 早期定义一个number类型的数组
let arr: number[] = [1, 2, 3]
// 用泛型定义一个number类型的数组
let arrTwo: Array<number> = [1, 2, 3]

假如我们现在要调换两个元素的位置,那么用泛型我们可以这么实现。具体代码如下:

function swap<T, U>(tuple: [T, U]): [U, T]{return [tuple[1], tuple[0]]
}const result2 = swap(['abc', 123])
console.log(result2[0]) //123
console.log(result2[1]) //abc

通过泛型,我们就顺利调换了两个元素的位置。

2、约束泛型

在泛型中使用 extends 关键字,就可以让传入值满足我们特定的约束条件,而不是毫无理由的随意传入。

比如,我们想要让我们定义的内容是一个数组,我们可以这么处理。具体代码如下:

function echoWithArr<T>(arg: T[]): T[]{console.log(arg.length)return arg
}
const arrs = echoWithArr([1, 2, 3])

这样,就把 arrs 定义为一个数组。


假设我们现在想要让我们定义的内容可以访问到 length 方法,那么我们需要加一点佐料。具体代码如下:

interface IWithLength{length: number
}function echoWithLength<T extends IWithLength>(arg: T): T{console.log(arg.length)return arg
}const str = echoWithLength('str')
const obj = echoWithLength({ length: 10, width: 20 })
const arr2 = echoWithLength([1, 2, 3])

通过 extends 关键字来继承特定的 interface ,使得我们定义的内容 str , obj ,arr2 达到可以访问length方法的目的。

通过以上举例,我们可以知道,泛型可以用来灵活的约束参数的类型,参数不需要是个特别死板的类型,而可以通过我们的约束来达到我们想要的目的。

3、泛型在类和接口中的使用

(1)泛型在类中的使用

class Queue<T>{private data = []push(item: T){return this.data.push(item)}pop(): T{return this.data.shift()}
}
// 确定这是一个number类型的队列
const queue = new Queue<number>()
queue.push(1)
console.log(queue.pop().toFixed())

(2)泛型在接口中的使用

interface KeyPair<T, U>{key: Tvalue: U
}
let kp1: KeyPair<number, string> = {key: 1, value: 'str'}
let kp2: KeyPair<string, number> = {key: 'str', value: 2}

通过以上代码演示可以发现,泛型就像是创建了一个拥有特定类型的容器,就仿佛给一个容器贴上标签一样。

八、类型别名

1、类型别名

类型别名,即 type aliase 。类型别名可以看作是一个快捷方式,可以把一个写起来很繁琐的类型创建一个简单的写法。比如:

//用以下这种写法,每次都要写一长串的(x: number, y: number) => number
let sum: (x: number, y: number) => number
const result = sum(1, 2)//用type给类型进行别名
type PlusType = (x: number, y: number) => number
let sum2: PlusType
const result2 = sum2(2, 3)//一个类型可以是字符串也可以是数字
type StrOrNumber = string | number
let result3: StrOrNumber = '123'
result3 = 123

2、字符串字面量

字符串字面量,指可以提供一系列非常方便使用的常量写法。比如:

const str: 'name' = 'name'
const number: 1 = 1
type Direction = 'Up' | 'Down' | 'Left' | 'Right'
let toWhere: Direction = 'Left'

3、交叉类型

交叉类型,使用 type 这个扩展对象的一种方式。比如:

interface IName{name: string
}
type IPerson = IName & {age: number}
let person: IPerson = {name: 'monday', age: 18}

九、声明文件

我们在写ts时,难免会有遇到要引入第三方库的时候。这个时候就需要ts来做特殊处理。主要有以下两种做法:

1、 .d.ts 文件引入

假设我们要引入JQuery库来使用,那么我们可以在外部新增一个 JQuery.d.ts 文件,文件内代码如下:

declare var JQuery: (selector: string) => any;

之后便可以在我们定义的 ts 文件下引用 JQuery 相关库的内容。比如:

jQuery('#foo')

2、npm安装

我们也可以安装对应的第三方库的 npm 包。假如我们现在要引入一个 JQuery 库,那么我们可以这么处理。

npm install --save @type/jquery

十、内置类型

我们在写 ts 代码时,其实不知不觉已经使用了很多的内置对象。对象呢,是指根据标准(标准指 ECMA 、 DOM 等标准),在全局作用域 global 上面存在的对象。那我们在运行 tsc 时,这些内置的对象就会被当作附加的礼物给程序加载进行。接下来我们来体会一下几种常见的内置对象。

全局对象:

// global object 全局对象
const a: Array<number> = [1, 2, 3]
const date = new Date()
date.getTime()
const reg = /abc/
reg.test('abc')

内置对象:

// build-in object 内置对象
Math.pow(2, 2)

DOM和BOM对象:

// DOM 和 BOM
let body = document.body
let allLis = document.querySelectorAll('li')
allLis.keys()document.addEventListener('click', e => {e.preventDefault()
})

功能性类型:

// Utility Types 功能性类型
interface IPerson{name: stringage: number
}let monday: IPerson = {name: 'monday', age: 20}//可选属性
type IPartial = Partial<IPerson>
let monday2: Ipartial = {name: 'monday'}//移除某一个属性
type Omit = Omit<IPerson, 'name'>
let monday3: Omit = {age: 20}

十一、结束语

关于 ts 的入门讲到这里就结束啦!希望大家能对 ts 有一个简单的认识!

如本文有不理解或有误的地方欢迎评论区评论或私信我交流!我们下期见!

  • 关注公众号 星期一研究室 ,不定期分享学习干货,学习路上不迷路~
  • 如果这篇文章对你有用,记得点个赞加个关注再走哦~

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

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

相关文章

编写第一个 .NET 微服务

介绍本文的目的是&#xff1a;通过创建一个返回列表的简单服务&#xff0c;并在 Docker 容器中运行该服务&#xff0c;让您熟悉使用 .NET 创建微服务的构建过程。安装 .NET SDK要开始构建 .NET 应用程序&#xff0c;首先下载并安装 .NET Core SDK&#xff08;软件开发工具包&am…

模板编译template的背后,究竟发生了什么事?带你了解template的纸短情长

解析模板编译template的背后发生了什么一、&#x1f4d1;初识模板编译1、vue组件中使用render代替template2、模板编译总结二、✏️感受模板编译的美1、with语法&#xff08;1&#xff09;例子展示&#x1f330;&#xff08;2&#xff09;知识点归纳三、&#x1f4c8;编译模板1…

leetcode24. 两两交换链表中的节点(思路+解析)

一:题目 二:思路 思路: 1.分析题意 这是相邻结点进行交换 如果是4个结点 那么1和2交换 3和4交换 如果是3个结点 那么就1和2进行交换 3不动 2.这里我们定义一个虚拟头节点方便操作&#xff0c;我们只需三步实现结点的交换 <1>:让虚拟结点指向第二个结点(进行交换的结点我…

把Autofac玩的和java Spring一样6

大家好&#xff0c;今天来介绍我开源的一个autofac.Annotation项目 源码&#xff1a;https://github.com/yuzd/Autofac.Annotation本项目是autofa的一个扩展组件&#xff0c;autofac是一个老牌的DI容器框架 &#xff0c;支持netframework和netcoreAnnotdation是注解的意思&…

『软件测试5』测开岗只要求会黑白盒测试?NO!还要学会性能测试!

浅谈软件测试中的性能测试一、&#x1f92a;性能测试概念1、为什么要有性能测试&#xff1f;2、性能测试是什么&#xff1f;3、性能测试的目的二、&#x1f910;性能测试指标1、响应时间2、吞吐量3、并发用户数4、TPS(Transaction Per Second)5、点击率6、资源利用率三、&#…

CLR的简单理解

CLR加载程序生成进程&#xff0c;一个进程中可以存在多个线程&#xff0c;当创建一个线程时&#xff0c;会分配1Mb的空间&#xff0c;也就是线程的栈空间&#xff0c;对应jvm的虚拟机堆栈&#xff0c;是线程执行过程中用到的工作内存。这片内存用于方法传递实参&#xff0c;并存…

『软件测试6』bug一两是小事,但安全漏洞是大事!

详解软件测试中的安全测试一、&#x1f4bf;安全测试概念1、安全测试概述2、安全测试与软件生命周期的关系3、常规测试与安全测试的不同&#xff08;1&#xff09;测试目标不同&#xff08;2&#xff09;假设条件不同&#xff08;3&#xff09;思考域不同&#xff08;4&#xf…

我们真的需要JWT吗?

JWT&#xff08;JSON Web Token&#xff09;是目前最流行的认证方案之一。博客园、各种技术公众号隔三差五就会推一篇JWT相关的文章&#xff0c;真的多如牛毛。但我对JWT有点困惑&#xff0c;今天写出来跟大家探讨探讨&#xff0c;不要喷哈。JWT原理本文默认读者已经对JWT有所了…

leetcode面试题 02.07. 链表相交

一:题目 二:思路 1.这道题我们是需要找到一个结点&#xff0c;并且从这个结点往后的结点都相等 2.我们需要将两个链表 右对齐 3.然后将长链表的指针移动到和短链表头结点相同的位置 4.接下来就是比较指针&#xff0c;当一个指针相同也就意味着往后的结点的数值也相等 三:上码…

详解队列在前端的应用,深剖JS中的事件循环Eventloop,再了解微任务和宏任务

队列在前端中的应用一、队列是什么二、应用场景三、前端与队列&#xff1a;事件循环与任务队列1、event loop2、JS如何执行3、event loop过程4、 DOM 事件和 event loop5、event loop 总结四、宏任务和微任务1、引例2、宏任务和微任务&#xff08;1&#xff09;常用的宏任务和微…

终于弄明白了 Singleton,Transient,Scoped 的作用域是如何实现的

一&#xff1a;背景1. 讲故事前几天有位朋友让我有时间分析一下 aspnetcore 中为什么向 ServiceCollection 中注入的 Class 可以做到 Singleton&#xff0c;Transient&#xff0c;Scoped&#xff0c;挺有意思&#xff0c;这篇就来聊一聊这一话题&#xff0c;自从 core 中有了 S…

leetcode142. 环形链表 II(暴力+双链表)

一:题目 二:思路 1.双指针 快慢指针(快指针一次一个结点&#xff0c;慢指针一次两个结点) 2.如果有环的话&#xff0c;那么快慢指针肯定会相遇 3.那么相遇的地点一定在环中 因为如果没有环的话慢指针是永远追不到快指针的 4.接下来就是判断出口在那里&#xff0c;我们定义一个…

动态 Restful API 生成

介绍通常在DDD开发架构中&#xff0c;我们写完服务层需要在控制器中写API&#xff0c;今天介绍一个组件 Plus.AutoApi 可以用它来动态生成 Restful 风格的 WebApi&#xff0c;不用写 Controller。快速使用在你的应用服务层中添加组件Install-Package Plus.AutoApi在 Startup 中…

卷死了!再不学vue3就没有人要你了!速来围观vue3新特性

一文全面了解vue3新特性一、&#x1f636;vue3比vue2有什么优势&#xff1f;二、&#x1f9d0;Vue3升级了哪些重要的功能1、createApp2、emits(父子组件间的通信)&#xff08;1&#xff09;通信方式&#xff08;2&#xff09;举个例子&#x1f330;3、多事件处理4、Fragment5、…

idea报错Class not found (在target中没有生成对应的class文件)

一&#xff1a;问题描述 二:解决 既然他不自动生成&#xff0c;那么我们就手动导入&#xff1b; 点击后应用 然后再次运行我们的测试用例&#xff1b;如果不行 再取消勾选 然后再运行我们的测试用例

敲黑板!vue3重点!一文了解Composition API新特性:ref、toRef、toRefs

一文了解Composition API新特性&#xff1a;ref、toRef、toRefs一、&#x1f64e;如何理解ref、toRef和toRefs1、ref、toRef和toRefs是什么&#xff08;1&#xff09;ref1&#xff09;ref是什么2&#xff09;举个例子&#x1f330;&#xff08;2&#xff09;toRef是什么1&#…

C# 枚举转列表

C# 枚举转列表独立观察员 2020 年 9 月 1 日今天有朋友问我&#xff0c;ComboBox 怎么绑定一个 Enum&#xff0c;其实他的意思是枚举如何转换为列表。想想这确实是一个挺正常的需求&#xff0c;但我一时也只想到遍历&#xff0c;他觉得麻烦&#xff0c;于是我在网上帮忙查了一下…

leetcode242. 有效的字母异位词(两种方法map或数组)

一:题目 二:上码 1:方法一&#xff08;map解法&#xff09; class Solution { public:bool isAnagram(string s, string t) {/**思路:1.分析题意&#xff0c;这个是要判断t中的字符出现次数和s中字符出现的次数相同2.可以用map<char,int>来做*/map<char,int>m1,m…

活久见!月薪30k的小程序全栈开发到底有多难?

10年前&#xff0c;公司的标配是门户网站&#xff0c;造就了一批网站工作室。随着移动互联网大潮兴起&#xff0c;App又成了企业标配&#xff0c;IOS和Android开发赚的盆满钵满。然而App导致的手机内存告急&#xff0c;无止尽的信息推送&#xff0c;让微信小程序应运而生。然而…

卷不动也得继续学!紧跟vue3的步伐,再来get一波进阶新特性!

vue3进阶新特性一、&#x1f4d7;watch和watchEffect1、watch和watchEffect的区别2、举个例子&#xff08;1&#xff09;wtach监听&#xff08;2&#xff09;watchEffect监听二、&#x1f4d8;setup如何获取组件实例&#xff08;1&#xff09;为什么需要获取组件实例&#xff0…