我们常说没有对象怎么搞new一个但是如果加一个static修饰符一句话总结不加 static属于实例造出来的对象加了 static属于类本身图纸本身不需要 new 就能用一、先看最核心区别class Person { name 张三; // 普通属性属于实例 static age 20; // 静态属性属于类 sayHi() {} // 普通方法属于实例 static sayHello() {} // 静态方法属于类 }1. 普通属性 / 方法不带 static必须new 出实例才能用const p new Person(); p.name; // ✅ 可以 p.sayHi(); // ✅ 可以2. 静态属性 / 方法带 static不需要 new直接用类名就能用Person.age; // ✅ 可以 Person.sayHello();// ✅ 可以二、最直观比喻秒懂类 汽车图纸static 印在图纸上的东西普通属性 / 方法 造出来的真车才有的东西static 颜色→ 写在图纸上不用造车就能看到普通颜色→ 必须造一辆车车身上才有颜色三、回到你自己的代码马上对应上export class ResultData { code: number; // 普通属性 → 属于实例 data: any; // 普通属性 → 属于实例 static ok() {} // 静态方法 → 属于类 static fail() {} // 静态方法 → 属于类 }所以你才能这样写ResultData.ok(data)不用 new直接用类调用四、static 三大关键规则必须记住1.静态方法里不能直接访问普通属性因为静态方法属于类普通属性属于实例类还没造出对象访问不到。tsclass A { name 123; static test() { console.log(this.name); // ❌ 报错 } }2.静态方法里只能访问静态属性 / 方法class A { static name 静态; static test() { console.log(this.name); // ✅ 正常 } }3.静态方法 / 属性全局只有一份不管 new 多少个实例static 永远只有一份大家共用。五、超级精简总结背会这 4 句加 static → 属于类不用 new 就能用不加 static → 属于实例必须 new 才能用静态方法不能访问普通属性静态属性全类共享只有一份六、你现在的代码为什么要写 statictsstatic ok() { return new ResultData(...) }因为想让外面直接写 ResultData.ok ()不用 new1.new ResultData(...)做了什么它会创建一个对象长这样{ code: 200, msg: 操作成功, data: 你传的内容 }2.return出去的是什么就是上面这个对象并且它的类型是ResultData类的实例。import { ApiProperty } from nestjs/swagger; export const SUCCESS_CODE 200; /** * 响应结构 * ok 成功 * fail 失败 */ export class ResultData { constructor(code SUCCESS_CODE, msg?: string, data?: any) { this.code code; this.msg msg || 操作成功; this.data data || null; } ApiProperty({ type: number, default: SUCCESS_CODE }) code: number; ApiProperty({ type: string, default: 操作成功 }) msg?: string; data?: any; static ok(data?: any, msg?: string): ResultData { return new ResultData(SUCCESS_CODE, msg, data); } static fail(code: number, msg?: string, data?: any): ResultData { return new ResultData(code || 500, msg || fail, data); } }代码static ok(data) { return new ResultData(200, 成功, data) }这里ResultData是类图纸new ResultData(...)造出来的那个对象→ 就是ResultData 的实例它长这样{ code: 200, msg: 成功, data: [...] }最终总结超精简类模板、图纸实例根据模板 new 出来的真实对象你代码里return的就是一个 new 出来的、真实可用的 ResultData 对象1. constructor 是干嘛的一句话constructor 就是 “类被 new 的一瞬间自动执行的函数”你写const res new ResultData(200, 成功, data)这时constructor 就会自动跑一遍把你传的参数赋值给实例。constructor(code 200, msg?: string, data?: any) { this.code code; this.msg msg; this.data data; }作用就两个初始化实例给 this.xxx 赋值没有 constructor你就只能手动赋值const res new ResultData() res.code 200 res.msg 成功有了 constructor一行搞定。2. public 是干嘛的一句话public 表示这个属性 / 方法 “外部可以访问”在 TS 里类的属性默认就是public所以你平时不写也没事。class ResultData { public code: number; // 外部能读能改 public msg: string; // 外部能读能改 }外部就能用const res new ResultData() res.code 200 // ✅ 允许 res.msg ok // ✅ 允许对比一下你就懂public谁都能访问默认private只有类内部能用外部不能碰protected内部 子类能用外部不能3. 在 TS 里有个超级常用简写你一定会遇到TS 允许你在 constructor 里直接写 public自动声明属性 自动赋值比如你原来要写class A { name: string; age: number; constructor(name: string, age: number) { this.name name; this.age age; } }用 public 简写后直接少一半代码class A { constructor( public name: string, public age: number ) {} }效果完全一样这就是 Nest 里最常见的依赖注入写法constructor(private userService: UserService) {}终极极简总结constructornew 的时候自动执行用来初始化、赋值public表示外部能访问这个属性 / 方法默认就是TS 里在 constructor 写 public/private 是语法糖自动声明 赋值一句话说清依赖注入 不用自己 new让 Nest 自动把你要用的类递给你。举个最直白的例子你平时写代码想要用 UserService本来应该自己 new// 不用依赖注入的原始写法 const userService new UserService(); userService.getList();但在 Nest 里你不自己 new而是这样写constructor(private userService: UserService) {}Nest 就自动把UserService实例给你了。这就叫依赖注入。为什么叫 “依赖注入”你这个 Controller依赖UserService 才能干活不是你自己创建而是 Nest主动注入给你所以叫依赖注入Dependency Injection核心好处为什么要用不用自己 new代码更干净类和类之间解耦好维护、好测试所有实例统一管理单例、复用Nest 模块化全靠它支撑用生活例子秒懂你要吃饭传统方式自己买菜 → 洗菜 → 做饭依赖注入饭做好了直接端给你张嘴吃就行Nest 就是那个保姆你要啥它给你递啥不用自己造。对应到你天天写的代码Controller(user) export class UserController { // 这一行就是依赖注入 constructor(private userService: UserService) {} Get() getList() { return this.userService.getList(); } }UserController依赖UserService你没写new UserService()Nest 自动创建并注入进来依赖注入的两个关键点1. 被注入的类必须加Injectable()告诉 Nest这个类可以被注入。Injectable() export class UserService {}2. 必须在 Module 里声明让 Nest 知道这个类存在。Module({ providers: [UserService], controllers: [UserController], }) export class UserModule {}终极极简总结依赖注入 类不用自己 new交给 Nest 自动创建、自动传递。你只需要在 constructor 里写constructor(private 要用到的类: 类名) {}就完事了。场景Controller 要调用 Service 里的方法1️⃣ 不使用依赖注入传统写法// user.service.ts export class UserService { getName() { return 张三; } }// user.controller.ts import { UserService } from ./user.service; Controller(user) export class UserController { private userService: UserService; constructor() { // 自己 new 一个 this.userService new UserService(); } Get() getInfo() { return this.userService.getName(); } }问题必须自己new UserService()如果 UserService 还依赖别的 Service你要一层层 new 下去耦合死了不好改、不好测试2️⃣ 使用 Nest 依赖注入实际开发写法第一步给 Service 加上可注入标记// user.service.ts Injectable() // 加上这个表示可以被注入 export class UserService { getName() { return 张三; } }第二步在 Module 里注册Module({ controllers: [UserController], providers: [UserService], // 在这里注册 }) export class UserModule {}第三步Controller 里直接 “拿” 过来用Controller(user) export class UserController { // 不用 new直接写在构造函数里就行 constructor(private userService: UserService) {} Get() getInfo() { return this.userService.getName(); } }差别到底在哪核心一句话不用 DI你自己造工具 → 自己 new用 DI你告诉 Nest 你需要什么工具 → Nest 造好递给你再夸张一点让你彻底看懂假如 UserService 还依赖其他服务不用 DI 你要写const a new AService(); const b new BService(a); const userService new UserService(b);用 DI 你只需要写constructor(private userService: UserService) {}Nest 自动把所有依赖链条全部建好。最终总结依赖注入 不用自己 new构造函数一写Nest 自动把实例给你。如果你愿意我可以再给你讲为什么要用 DI它到底解决了什么实际痛点依赖注入和控制反转IoC有什么关系这俩是绑定在一起的我用最通俗、不绕弯的方式给你讲清楚保证你彻底懂。一句话关系控制反转IoC是思想依赖注入DI是实现这个思想的具体手段IoC 把 “创建对象的权力” 交出去DI 具体怎么交通过构造函数塞给你1. 先讲什么是「控制反转」原来的写法你自己控制你需要 UserService →你自己 neconstructor() { this.userService new UserService(); } 对象的创建、管理全是你自己控制。反转之后Nest 控制你需要 UserService →Nest 帮你 new再递给你constructor(private userService: UserService) {}控制权从你 → 反转给了 Nest 框架这就叫控制反转 IoCInversion of Control2. 再讲依赖注入 DI 是什么就是 Nest 把你需要的对象“注入” 到你的类里。方式一般有三种构造器注入最常用属性注入Setter 注入Nest 默认用构造器注入。3. 两者关系总结超级好记IoC 是原则谁来创建对象以前是我现在交给容器Nest这叫反转。DI 是动作怎么把对象给你通过构造函数塞进来这叫注入。4. 最经典比喻秒懂你要喝水以前没 IoC自己挖井 → 抽水 → 烧水 → 喝控制权在你现在IoC有人把水递到你手上控制权反转给送水的DI 就是送水的把水杯塞进你手里这个动作。5. 对应到你的代码constructor(private userService: UserService) {}IoC 体现你不再new UserService()交给 Nest 管理DI 体现Nest 把创建好的 userService 实例通过构造函数注入进来终极极简总结IoC思想 —— 把创建对象的权力反转给框架DI写法 —— 框架通过构造函数把对象注入给你IoC 是设计理念DI 是实现 IoC 的方式。Repository是不是也是依赖注入呢是的而且完全是一回事Repository 在 Nest 里100% 属于依赖注入用法、原理、流程跟 Service 一模一样。我用最简单的话给你讲透。1. 先给结论Repository 就是被 Nest 自动创建、自动注入的对象你不用自己 new直接写在构造函数里拿 → 这就是依赖注入。2. 看一眼你平时写的代码Injectable() export class UserService { constructor( // 这就是依赖注入 InjectRepository(UserEntity) private readonly userRepository: RepositoryUserEntity, ) {} }这里RepositoryUserEntity是你要依赖的对象你没有 newNest 自动帮你创建好通过构造函数注入给你这不就是依赖注入吗完全是3. 它和注入 Service 有区别吗没有任何本质区别注入 Serviceconstructor(private userService: UserService) {}注入 Repositoryconstructor( InjectRepository(UserEntity) private userRepository: RepositoryUserEntity ) {}唯一不同Service 是你自己写的用Injectable()Repository 是 TypeORM 自动生成的用InjectRepository(实体)标记本质都是依赖注入。4. 为什么它也算 DI因为满足依赖注入所有特征不自己 new控制权交给框架Nest TypeORM通过构造函数声明需要什么框架自动创建并传递进来 这就是IoC DI5. 超精简总结Service 是依赖注入Repository 也是依赖注入甚至 ConfigService、JWTService 全都是依赖注入在 Nest 里只要你写在 constructor 里、不用自己 new 的东西全是依赖注入。IoC Inversion of Control控制反转一句话解释以前对象是你自己 new 的现在对象是 Nest 帮你 new 的。控制权从「你」反转给了「Nest 容器」这就叫 IoC。用两段代码对比你瞬间懂1️⃣ 没有 IoC 的时代你控制你想要 UserRepository必须自己造// 你自己手动创建 const repo new UserRepository(); repo.find();对象是谁创建的你谁管理生命周期你→ 控制权在你手里2️⃣ 有 IoC 的时代Nest 控制你只需要说 “我要”Nest 递给你constructor( InjectRepository(User) private repo: RepositoryUser ) {}对象是谁创建的Nest谁管理Nest你只负责用→控制权从你 → 反转给 Nest这就叫IoC控制反转最通俗的比喻没 IoC你要吃饭 → 自己买菜、做饭、洗碗你控制一切有 IoC你说 “我要吃饭” → 保姆直接端上来保姆控制一切你只管吃这里保姆 Nest 的 IoC 容器饭菜 要注入的实例Service、Repository…你只管张嘴 依赖注入DIIoC 和 DI 的关系终极总结IoC 是思想把创建对象的权力交出去DI 是做法通过构造函数把对象递给你IoC 是设计思想DI 是实现 IoC 的方式。放到你写的 Repository 里constructor( InjectRepository(User) private userRepo: RepositoryUser )你没有new RepositoryNest 自动创建、管理控制权反转 →IoC通过构造函数塞给你 →DI最精简一句话IoC 就是不再自己 new 对象让框架去 new、去管。DTO 是前端传进来的参数Entity 是数据库里的表结构。完全不是一回事各司其职一句话终极区分DTO 前端给后端的数据入参 / 出参Entity 后端对应数据库的表字段 / 结构1. 先讲 DTOData Transfer Object是干嘛的用来校验前端传过来的数据对不对比如注册接口要传username和password你必须规定username 不能为空password 长度至少 6 位这些规则就写在 DTO 里。代码长这样// user.dto.ts export class CreateUserDto { ApiProperty({ description: 用户名 }) IsString() IsNotEmpty() username: string; ApiProperty({ description: 密码 }) IsString() Length(6, 20) password: string; }DTO 只做一件事接收前端参数 → 校验格式对不对不和数据库打交道2. 再讲 Entity是干嘛的对应数据库里的一张表定义表里有哪些字段比如 user 表idusernamepasswordcreate_time代码长这样// user.entity.ts Entity(user) // 对应数据库 user 表 export class User { PrimaryGeneratedColumn() id: number; Column({ length: 50 }) username: string; Column() password: string; CreateDateColumn() createTime: Date; }Entity 只做一件事映射数据库表结构给 Repository 操作数据库用。3. 最直观的流程你一看就懂前端传参 → DTO校验格式→ Service业务处理→ Entity操作数据库举个注册例子前端传{ username: zhangsan, password: 123456 }DTO 先校验有没有传长度对不对Service 拿到合法数据转成 Entity 格式Repository 把 Entity 存进数据库4. 为什么要分成两层重点如果不分开把数据库字段直接暴露给前端想加校验没地方加字段改一个全链路爆炸代码完全乱套分开后DTO 只管前端参数Entity 只管数据库表互相不影响安全、清晰、易维护5. 超精简总结背会这两句✅ DTO 前端 → 后端入参校验✅ Entity 后端 → 数据库表结构