Skip to content

面试 ​

说说你对双向绑定的理解 ​

java

我可以先解释一下单向数据绑定。
单向数据绑定是把数据绑定到视图上,当数据更新时,视图就会自动更新。
在单向数据绑定的基础上,当视图更新时,数据也会自动更新,这就是双向数据绑定。

说说 Typescript 中的装饰器 ​

java

装饰器其实就是一个函数,它可以用在类、方法或者属性上,来扩展它们的功能。
比如我可以用它来做日志记录、权限控制,或者缓存一些中间结果。
它的最大优点是能把跟业务无关的代码从核心逻辑里抽离出来,这样代码更清晰简洁、也更好维护。

说说你对依赖注入的理解 ​

java

我理解的依赖注入,其实就是说,当一个服务需要用到其他组件的时候,
它自己不负责创建这些依赖,而是由外部把这些依赖传进来。

举个例子,比如我有一个服务要用数据库对象。
如果我在服务里直接 new 一个数据库对象,那这个服务就跟这个数据库实现耦合得很死。

但如果我通过构造函数把数据库对象传进来,我就可以自由替换这个依赖,
比如在写单元测试时用一个内存数据库或者 mock 对象来替代。

这样做的好处是,耦合度低、职责清晰,而且特别适合测试,能让代码更灵活、可维护性更强。

你是否自己实现过简化版的依赖注入容器 ​

java

我会先创建一个Map作为容器对象,用来保存服务的构造函数或实例。

然后提供一个register方法注册服务,一个resolve方法创建实例,
resolve方法会自动查找构造函数的参数,递归地实例化依赖。

简化版依赖注入容器

typescript
class Container {
  private providers = new Map();

  register(token: any, provider: any) {
    this.providers.set(token, provider);
  }

  resolve(token: any): any {
    const Provider = this.providers.get(token);
    const deps = Reflect.getMetadata("design:paramtypes", Provider) || [];
    const instances = deps.map((dep: any) => this.resolve(dep));
    return new Provider(...instances);
  }
}

进阶版带装饰器的依赖注入容器

typescript
import "reflect-metadata";

class Container {
  private providers = new Map();

  register(token: any) {
    this.providers.set(token, token);
  }

  resolve<T>(token: new (...args: any[]) => T): T {
    const target = this.providers.get(token);
    const deps = Reflect.getMetadata("design:paramtypes", target) || [];
    const instances = deps.map((dep: any) => this.resolve(dep));
    return new target(...instances);
  }
}

// 装饰器:用于自动注册类
function Injectable(target: any) {
  container.register(target);
}
typescript
const container = new Container();

@Injectable
class DatabaseService {}

@Injectable
class UserService {
  constructor(private db: DatabaseService) {}
}

const userService = container.resolve(UserService);