2025 独立开发者训练营:AI Agent!查看介绍 / 立即报名 →

博客

JavaScript:理解属性描述器(Property Descriptor)

一个 JavaScript 对象里面可能有一堆属性,属性都有一个名字,还有对应的值,除了这些其实还隐含了一些东西,这就是 Property Descriptor。来做个实验:

const user = {
  name: 'ninghao',
};

const descriptor = Object.getOwnPropertyDescriptor(user, 'name');

console.log(descriptor);

上面定义了一个叫 user 的对象,里面只有一个属性叫 name,对应的值是个字符串 ninghao。如果要检查一下 name 这个属性的 Descriptor,可以使用 Object 上的 getOwnProperyDescriptor 方法,把对象还有对象的属性交给这个方法就可以了。

执行上面的代码,会返回:

TypeScript:理解 Decorator 装饰器

Decorator 装饰器,在 TypeScript 里装饰器就是函数,装饰器可以装饰类,类的属性、方法还有方法的参数等等。装饰器可以处理它装饰的东西,比如给它装饰的东西添加点额外的东西或者修改或替换它装饰的东西。在 Nest.js 应用框架里大量地使用了装饰器。

定义类装饰器

类装饰器就是装饰类用的装饰器,这种装饰器接收一个构造方法参数。

function log(target: any) {
  console.log('hello ~', target);
}

log 其实就是一个函数,只不过根据装饰器要装饰的东西的不同,装饰器函数接收的参数会有一些不同。比如我们这个 log 要装饰类,也就是它是一个类装饰器,那它接收的这个 target 参数就是类的构造方法。log 目前的作用就是在代码运行的时候输出一个 hello,后面加上它接收的 target 参数的值。

新课:Netflix 原创剧里出现的应用框架(Nest.js)

Nest.js 是一款服务端应用框架,你可以用它创建企业级应用(加上 “企业” 显得高级一些 :)。我非常喜欢这款框架,决定再深入研究一下,最终会为你提供一套完整的服务端应用开发的工具、方法与流程。

Nest.js 是基于 Node.js 创建的,Node.js 是一种 JavaScript 语言的运行环境,在服务器上安装一个 Node.js,就可以去运行用 JavaScript  语言写的程序了。也就是用 Nest.js 创建应用,用的语言就是 JavaScript,不过我们用的是带 “外挂” 版本的 JavaScript,也就是 TypeScript。

早先 JavaScript 语言一般会在浏览器上运行,网页上多少都会嵌入点用 JavaScript 语言写的脚本,它是网页界面的组成部分。这些脚本主要是去处理网页界面上发生的一些事情,就是给网页添加点交互功能。

NNC D16:文件上传

D16 要去实现文件上传的功能,在应用的数据库里需要存储用户上传的文件相关的信息。使用 FileInterceptor 这个拦截器可以处理请求里的文件。用 UploadedFile 这个装饰器可以得到上传的文件相关的数据。

  @Post()
  @UseInterceptors(FileInterceptor('file'))
  async store(
    @UploadedFile() data: FileDto
  ) {
    return await this.fileService.store(data);
  }

在客户端上传文件的时候,请求应该设置成 Multipart form,里面添加一个 file 字段,它的值就是要上传的文件。给 FileInterceptor 拦截器提供的参数值是 file ,所以上传的时候就需要包含一个叫 file 的字段 。

相关的配置:

NNC D15:权限控制

D15 一起实现一个简单的权限控制功能,可以要求发出请求的用户必须拥有某个用户角色,或者用户是当前请求的资源的拥有者,满足这些条件的时候应用才会把用户请求的资源返回到客户端。

用户角色可以是一种实体,我们可以先创建一个模块来处理这种实体资源。然后在这个实体里去定义角色与用户这两种实体之间的关系。

@Entity()
export class Role {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ type: 'enum', enum: UserRole, unique: true })
  name: UserRole;

  @Column()
  alias: string;

  @ManyToMany(type => User, user => user.roles)
  users: User[]
}

用户实体中的关系:

NNC D14:排序与分页

D14 去实现的内容列表的排序与分页功能。在用 TypeOrm 提供的方法查询出内容列表的时候,查询用的方法可以先去创建一个 QueryBuilder,然后用 take 方法设置一下每次返回的列表项目数量,用 skip 可以设置跳过的项目数量。

    queryBuilder
      .take(limit)
      .skip(limit * (page - 1));

这种分页内容的方法需要两个变量,一个是每页显示的列表数量,还有一个是当前的页码。这两个变量可以动态得到值,比如它们可以来自地址查询符。在 Nest.js 应用里,可以创建一个自定义的参数装饰器,去获取到请求地址里的查询参数的值。

export const ListOptions = createParamDecorator((data: Partial<ListOptionsInterface> = {}, req) => {
  let { page, limit } = req.query;
  ...
}

分页内容还有一个关键是得到总共的结果数量,使用 QueryBuilder 上的 getManyAndCount 这个方法可以返回查询结果还有结果数量。

NNC D13:评论

D13 的任务是在应用里添加一个评论功能,评论也是应用里的一种实体,围绕这种实体可以去创建一个评论模块。

src/modules/comment/comment.entity.ts

NNC D12:标签

D12 要做的训练内容是去创建一个标签模块,标签在应用里也是一种实体,每个标签可以有自己的名字、别名等等,你也可以加上标签的描述、缩略图之类的东西。

这次训练的重点是要理解多对多的关系,我们可以在每个文章内容上面打上多个标签,每个标签都可以关联一组文章内容。

先在标签实体上定义它跟文章内容的关系:

  @ManyToMany(type => Post, post => post.tags)
  posts: Post[];

标签上的这个关系的名字叫 posts,它的类型是一组 Post 实体。在 Post 实体上对应的关系应该叫 tags 。

在文章内容实体上定义与标签的关系:

  @ManyToMany(type => Tag, tag => tag.posts)
  @JoinTable()
  tags: Tag[];

同样使用 @ManyToMany 这个装饰器去定义多对多的关系,这个关系的名字叫 tags,类型是一组 Tag 实体。注意这里定义关系的时候用了一个 @JoinTable 装饰器,它可以创建一个中间表来保存内容与标签之间的多对多的关系。

NNC D11:分类

D11 要在应用里添加分类功能。分类也可以看成是应用里的一种实体,我们可以创建一个模块专门去处理分类相关的东西。

src/modules/category/category.entity.ts

import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
import { Post } from '../post/post.entity';

@Entity()
export class Category {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column()
  alias: string;

  @OneToMany(type => Post, post => post.category)
  posts: Post[];
}

上面定义了一个简单的分类实体,里面有 id、name 还有 alias 字段。name 是分类的名字,alias 表示分类的一个别名,比如一个中文分类可以对应一个英文的别名。

NNC D10:定义与使用 Nest.js 应用里的内容关系

从 D10 开始往后会训练使用内容的关系。在应用里的内容与内容之间存在某种关系,比如用户与文章,文章与评论,用户与评论,分类与文章,标签与文章等等。我们需要根据关系的类型去定义这些内容与内容之间的关系,这样在创建内容的时候才能存储内容的关系,存储了内容的关系以后就可以利用内容的关系。

比如用户(User)是一种实体,文章(Post)也是应用里的一种实体。这两种实体之间存在某种关系,一个用户可以发布多个文章内容,就是可以关联多个文章内容,一个文章内容只能属于一个用户。对于用户实体来说,它跟内容是一对多(OnToMany)的关系,对于文章实体,它跟用户是多对一(ManyToOne)的关系。

在 Nest.js 应用里。在实体的定义里可以描述内容之间的这个关系,下面是在 User 实体里面,描述他跟 Post 实体的关系:

src/modules/user/user.entity.ts

微信好友

用微信扫描二维码,
加我好友。

微信公众号

用微信扫描二维码,
订阅宁皓网公众号。

240746680

用 QQ 扫描二维码,
加入宁皓网 QQ 群。

统计

15260
分钟
0
你学会了
0%
完成

社会化网络

关于

微信订阅号

扫描微信二维码关注宁皓网,每天进步一点