Nest(3):扫盲篇:TypeScript 类和装饰器

前言

先回顾下前文中介绍了哪些内容:

  • 使用 @nestjs/cli 创建和管理 Nest 应用
  • Hello, World 示例代码分析
  • Nest 基本概念:模块,控制器,服务
  • 常用的装饰器:@Module、@Controller、@Get、@Injectable
  • Nest 目录结构分析
  • @nest/cli 脚手架的命令

本文先不继续讲解 Nest 中的内容,而是打算介绍 TypeScript 中的两个语法:类和装饰器,帮助新手理解 Nest 中代码的写法。

如果你对 TypeScript 已经很熟悉,根据自己实际情况有选择的阅读即可。

类 Class

NestJS 支持面向对象编程,也支持函数式编程。但在实际开发中还是以面向对象为主,而面向对象又是和类紧密联系的,所以对于类的一些概念和语法,一定要熟练掌握。

ES6 推出了 class 类,本质是过去的构造函数的语法糖。TypeScript 中的类的用法和 ES 标准中的类大差不离,多了一些更加 OOP 的语法支持。、

下面是对类的一些常用语法的说明。

类成员

在 JS 中类的成员有两种,分别是成员属性成员方法。TypeScript 官方文档中会称之为字段(filed)和方法(method)。本文描述时会按照 JS 的习惯。

属性

在 TS 中声明类使用 class 关键字,如果实例有属性,则必须先声明其属性类型。如下,声明一个 Person 类:

class Person {// 声明类的属性,可以使用类型注解声明类型name: string;age: number;// 也可以省略,则默认是 any 类型address;
}// 实例化
const person = new Person('kw', 18);
console.log(person.name);

初始值

类的属性可以设置初始值,既可以在声明时设置,也可以在构造函数中设置:

class Person {name: string = 'kw';age: number = 18;
}class Person { name: string;age: number;constructor() {this.name = 'kw';this.age = 18;}
}

--strictPropertyInitialization

这是 tsconfig.json 中的一个配置项,是否严格检查类的属性初始化操作。默认为 true,表示类的成员属性必须在声明时或者在构造函数中进行初始化操作。如果该选项开启了:

class Person { // 正确,在声明时完成了初始化name: string = 'kw';// 正确,在构造函数中完成了初始化age: number;// 报错:Property 'address' has no initializer and is not definitely assigned in the constructor.address: string;constructor() {this.age = 18;}
}

有些场景下需要在别的地方进行属性的初始化,此时可以对属性应用非空断言:

class Person {name!: string;
}

此时虽然没有做初始化,但是编译器也不会报错了。

readonly 修饰符

使用 readonly 修饰类的成员属性后,该属性就变为了只读属性,只能读,不能修改。因此对于只读属性,必须在声明时,或者在构造函数中进行初始化,否则会报错。

class Person { readonly name: string = 'kw';age: number;
}

构造方法

构造方法用于创建和初始化类的实例对象。使用 new 操作一个类时,就会触发这个类的构造方法的执行。

构造方法不是必须的,类有一个默认的空的构造方法。但是如果需要为类的实例设置不同的属性,则必须实现一个构造方法。

class Person { name: string;age: number;constructor(name: string, age: number) {this.name = name;this.age = age;}
}// 实例化
const person = new Person();
console.log(person.name);
console.log(person.age);

可访问性修饰符

修饰符用来限制类的成员属性和成员方法的可访问范围

假设有一个 A 类和继承自 A 的 B 类,则可见范围有三种:任意地方,A 类内部,B 类的内部。分别对应了三种修饰符:

  • public:默认的修饰符,表示成员是公有的,可在任意地方被访问
  • protected:受保护的修饰符,表示成员能在当前类的内部,子类的内部被访问到
  • private:私有修饰符,表示成员只能在类的内部被访问到

image-20230116230814660

class A {// 默认为 public,等同于 public aa;// 受保护的属性,可以在当前类和子类中访问protected b;// 私有属性,只能在当前类内部访问private c;test() {console.log(this.c)}
}class B extends A {test() {console.log(this.b)}
}

参数属性

参数属性(Parameter Properties)是一种能简化代码的语法糖。例如要声明一个类,要先声明成员属性,再写构造方法进行初始化:

class Person { name: string;age: number;constructor(name: string, age: number) {this.name = name;this.age = age;}
}const person = new Person('kw', 18)
console.log(person.name)
console.log(person.age)

当这个类有非常多的属性时,光这些初始化代码可能就要写几十行。

在 TypeScript 中,在构造函数的参数前加上一个可见性修饰符publicprivateprotected 或者 readonly,该参数就变为了参数属性,TypeScript 会将这些构造函数的参数转换为具有相同名称和值的类属性

上面的 Person 类就等同于这种写法:

class Person { // 在声明类成员时 public 修饰符可以省略,但在使用参数属性时,不能省略constructor(public name: string, public age: number) {// 不需要函数体}
}const person = new Person('kw', 18)
console.log(person.name)
console.log(person.age)

回顾下 AppController 控制器的代码:

export class AppController {constructor(private readonly appService: AppService) {}
}

现在再看这段代码是什么含义就很清晰了,它的完整写法是:

export class AppController {// appService 是私有属性且只读,需要在声明或者构造函数中完成初始化private readonly appService: AppService;constructor(appService: AppService) {this.appService = appService;}
}

类的其他语法

类还有一些其他语法,比如访问器,静态成员属性和方法,继承等等。这些内容如果还不熟悉,可以阅读其他文章博客或者文档,我们先学习上面这些,够用为主。

装饰器 Decorator

装饰器,看名字就知道是用起装饰作用的。它用来增强类(class)的功能,许多面向对象的语言都有这种语法。

虽然装饰器的历史悠久,但是由于 JS 这门语言本身很少有场景需要使用到装饰器,所以目前装饰器仍处于提案阶段,并且这一提,就是很多年。记得最早在 ES2015 中,装饰器语法就已经处于提案阶段了。

虽然 ES 标准的装饰器还未成为标准,但是 TS 中的装饰器可以大胆使用。

装饰器的本质就是函数,只不过使用形式上和普通函数有所不同:普通函数使用 () 调用,装饰器使用 @ 调用。普通函数可以在任意位置执行,装饰器只能用在类和类的成员身上

装饰器和装饰器工厂

先来看一个装饰器的最简单的例子。

function Fn(target: any) {let a = new target;a.say()
}@Fn
class A {say() {console.log('hello')}
}

代码执行,打印 “hello”。

Fn 是一个装饰器函数,当被用在类上时,它所接收的参数就是该类。所以可以在装饰器内部,实例化 A 类型,并调用 a对象 的实例方法。

如果需要一些定制化的内容,想让装饰器接收一些其他的参数,就要用到装饰器工厂了。装饰器工厂就是一个返回装饰器的工厂函数。比如:

function FnFactory(name: string) {// 返回一个装饰器return function(target: any) {let a = new target;a.say(name)}}@FnFactory('kw')
class A {say(name: string) {console.log('hello, ', name)}
}

代码执行,打印 “hello, kw”。

注意区分装饰器和装饰器工厂的使用,普通的装饰器的用法是 @装饰器,装饰器工厂的用法需要带上圆括号,@装饰器()

类装饰器

根据所修饰对象的不同,装饰器具体可以分为:

  • 类装饰器
  • 属性装饰器
  • 方法装饰器
  • 存取器装饰器
  • 参数装饰器

上面的示例中,装饰器在类上调用,这就是类装饰器。类装饰器只有一个参数,就是被装饰的类

属性装饰器

应用在类的属性成员上的装饰器,可接收两个参数:

  • 如果是静态属性,则是类的构造方法;如果是实例属性,则是类的原型对象
  • 属性名
function Property() {return function (target: any, property: any) {console.log(target)console.log(property)}
}class C {@Property()name!:string;
}// {}
// name

方法装饰器

方法装饰器用的比较多,它接收3个参数:

  • 如果修饰的是静态成员,则为类的构造函数;如果修饰的是实例方法,则为类的原型对象
  • 方法名
  • 方法的属性描述符
function enumerable(value: boolean) {return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {descriptor.enumerable = value;};
}class Greeter {greeting: string;constructor(message: string) {this.greeting = message;}@enumerable(false)greet() {return "Hello, " + this.greeting;}
}

这个装饰器的作用是修改属性描述符的 enumerable 属性,设为 false,也就代表着该方法不能被枚举了。

存取器装饰器

用在访问器身上的装饰器,可接收参数和方法装饰器相同。

function configurable(value: boolean) {return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {descriptor.configurable = value;};
}class Point {private _x: number;private _y: number;constructor(x: number, y: number) {this._x = x;this._y = y;}@configurable(false)get x() {return this._x;}@configurable(false)get y() {return this._y;}
}

该装饰器可以动态修改存取器的属性描述符的 configurable 属性,示例中将其设置为 false,表示不能被删除,也不能被修改。

参数装饰器

应用在构造方法或者实例方法的参数上的装饰器,它接收三个参数:

  • 如果修饰的是静态成员方法,则为类的构造函数;如果修饰的是构造方法或者实例方法,则为类的原型对象
  • 参数所在方法的名字
  • 参数在原函数的参数列表中的位置,也就是第几个参数
// 参数装饰器
function Param() {return function(target: any, param: string, index: number) {console.log(target)console.log(param)console.log(index)}
}class Person {say(@Param() msg:string) {console.log(msg)}
}// {}
// say
// 0

@Controller 和 @Get 装饰器

看了这么多装饰器,已经眼花缭乱了,来看一个实际的例子。

打开 app.controller.ts,修改为以下内容:

import { Controller, Get, Query } from '@nestjs/common';
import { AppService } from './app.service';// 声明类为控制器,并为该模块的路由设置一个请求前缀 news
@Controller('news')
export class AppController {constructor(private readonly appService: AppService) {}// 和路由前缀拼接,处理 Get /news/list 请求@Get('list')// 参数装饰器,入参是请求中的 query 参数getHello(@Query('page') page) {return {code: 0,data: {list: [],page,},};}
}

打开浏览器,访问 localhost:3000/news/list?page=10

image-20230117011356232

当然,Nest 中还有非常多的装饰器,后面也会继续介绍。

总结

本文没有继续介绍 NestJS 有关的内容,而是讲解了 TypeScript 中两个很重要的语法:类和装饰器,可以帮助新手理解 Nest 应用中的一些代码写法的含义。

毕竟不积跬步,无以至千里,打好这些基础,后面上手的也会更顺利。

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

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

相关文章

21.2 CSS 三大特性与页面布局

1. 开发者工具修改样式 使用开发者工具修改样式, 操作步骤如下: * 1. 打开开发者工具: 在浏览器中右键点击页面, 然后选择检查或者使用快捷键(一般是 F12 或者 CtrlShiftI)来打开开发者工具.* 2. 打开样式编辑器: 在开发者工具中, 找到选项卡或面板, 一般是Elements或者Elemen…

【仿写框架之仿写Tomact】一、详解Tomcat的工作流程

文章目录 1、启动阶段2、监听阶段:3、请求处理阶段:4、发送请求处理后的响应 当涉及到Java Web应用程序的部署和运行,Apache Tomcat无疑是一个备受欢迎的选择。Tomcat作为一个开源的、轻量级的Java Servlet容器和JavaServer Pages (JSP) 容器…

[保研/考研机试] KY124 二叉搜索树 浙江大学复试上机题 C++实现

题目链接&#xff1a; 二叉搜索树_牛客题霸_牛客网判断两序列是否为同一二叉搜索树序列。题目来自【牛客题霸】https://www.nowcoder.com/share/jump/437195121692722892652 描述 判断两序列是否为同一二叉搜索树序列 输入描述&#xff1a; 开始一个数n&#xff0c;(1<…

Sectigo EV代码签名申请步骤

一、EV代码签名申请前提 1、单位成立时间不低于&#xff1a;3个月 2、单位工商及企查查可查 3、单位经营正常 4、注册地址真实存在&#xff0c;禁止使用集中注册地址 5、企查查登记电话和邮箱&#xff0c;确定查询结果的电话可以接听、邮箱可以接收邮件&#xff0c;如果信…

行业追踪,2023-08-22

自动复盘 2023-08-22 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

v8引擎编译全过程

环境vs2019 cmd 命令行需要设置成为代理模式 set http_proxyhttp://127.0.0.1:10809 set https_proxyhttp://127.0.0.1:10809 这个必须带上&#xff0c;不然报错&#xff0c;告诉编译器win系统的模式 set DEPOT_TOOLS_WIN_TOOLCHAIN0 源码 GitHub: GitHub - v8/v8: The…

SpringBoot复习:(53)TransactionInterceptor是在哪里配置的?

我们知道SpringBoot的事务(Transactional)最终是通过TransactionInterceptor的invoke方法调用invokeWithinTransaction方法来开启事务控制的。 TransactionInterceptor bean在哪里配置的呢&#xff1f;在ProxyTransactionManagementConfiguration: 可以看到这里创建了一个Tra…

SpringBoot 跨域问题和解决方法

Spring Boot 是一种用于构建独立的、生产级别的Java应用程序的框架。在开发Web应用程序时&#xff0c;经常会遇到跨域资源共享&#xff08;CORS&#xff09;问题。本文将详细介绍Spring Boot中的跨域问题以及相应的解决方法。 目录 什么是跨域&#xff1f;1. 使用Spring Boot…

常见前端面试之VUE面试题汇总二

4. slot 是什么&#xff1f;有什么作用&#xff1f;原理是什么&#xff1f; slot 又名插槽&#xff0c;是 Vue 的内容分发机制&#xff0c;组件内部的模板引擎使用 slot 元素作为承载分发内容的出口。插槽 slot 是子组件的一个模板 标签元素&#xff0c;而这一个标签元素是否显…

分类预测 | MATLAB实现DBN-SVM深度置信网络结合支持向量机多输入分类预测

分类预测 | MATLAB实现DBN-SVM深度置信网络结合支持向量机多输入分类预测 目录 分类预测 | MATLAB实现DBN-SVM深度置信网络结合支持向量机多输入分类预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.分类预测 | MATLAB实现DBN-SVM深度置信网络结合支持向量机多输入分…

LLaMA-7B微调记录

Alpaca&#xff08;https://github.com/tatsu-lab/stanford_alpaca&#xff09;在70亿参数的LLaMA-7B上进行微调&#xff0c;通过52k指令数据&#xff08;https://github.com/tatsu-lab/stanford_alpaca/blob/main/alpaca_data.json&#xff09;&#xff0c;在8个80GB A100上训…

【仿写tomcat】一、tomcat工作流程

仿写tomcat 简介tomcat简介流程分析tomcat是怎么和访问者交互的&#xff1f;流程图 简介 作者前不久刚仿写了一个简易的tomcat&#xff0c;在此分享给各位&#xff0c;此篇为对tomcat的简介和流程分析&#xff0c;具体仿写内容后续会贴在这里 扫描java文件&#xff0c;获取带…

常量变量习题答案

基础题目: 第一题 按步骤编写代码&#xff0c;效果如图所示&#xff1a; 编写步骤&#xff1a; 定义类 Test1定义 main方法控制台输出5行字符串类型常量值控制台输出5行字符类型常量值 参考答案&#xff1a; public class Test1 {public static void main(String[] args) {/…

TheGem主题 - 创意多用途和高性能WooCommerce WordPress主题/网站

TheGem主题概述 – 适合所有人的TheGem 作为设计元素、样式和功能的终极 Web 构建工具箱而设计和开发&#xff0c;TheGem主题将帮助您在几分钟内构建一个令人印象深刻的高性能网站&#xff0c;而无需触及一行代码。不要在编码上浪费时间&#xff0c;探索你的创造力&#xff01…

【Visual Studio】生成.i文件

环境 VS版本&#xff1a;VS2013 问题 如何生成.i预编译文件&#xff1f; 步骤 1、打开VS项目属性&#xff0c;打开C/C\预处理器页面&#xff0c;【预处理到文件】选择是&#xff0c;开启。 2、生成文件如下。 3、正常编译需要关闭此选项。

Azure VM上意外禁用NIC如何还原恢复

创建一个windows虚拟机&#xff0c;并远程连接管理员的方式打开powershell 首先查看虚拟网卡&#xff0c;netsh interface show interface 然后禁用虚拟网卡 ,netsh interface set interface Ethernet disable 去Azure虚拟机控制台&#xff0c;打开串行控制台 控制台中键入cmd,…

JAVA开发环境接口swagger-ui使用总结

一、前言 swagger-ui是java开发中生产api说明文档的插件&#xff0c;这是后端工程师和前端工程师联调接口的桥梁。生成的文档就减少了很多没必要的沟通提高开发和测试效率。 二、 swagger-ui的使用 1、引入maven依赖 <dependency><groupId>io.springfox</grou…

开源语音聊天软件Mumble

网友 大气 告诉我&#xff0c;Openblocks在国内还有个版本叫 码匠&#xff0c;更贴合国内软件开发的需求&#xff0c;如接入了国内常用的身份认证&#xff0c;接入了国内的数据库和云服务&#xff0c;也对小程序、企微 sdk 等场景做了适配。 在 https://majiang.co/docs/docke…

ubuntu 搜狗输入法安装 和 无法输入中文

一、下载搜狗输入法Linux版本。 搜狗输入法linux-首页 二、安装fcitx输入框架&#xff0c;及相关的依赖库 sudo apt install fcitx-bin sudo apt-get install fcitx-table sudo apt --fix-broken install 三、安装搜狗输入法 sudo dpkg -i sougou....deb 四、通过 设置&…