使用函数/类作为"值的含义"在Javascript Map()

时间:2016-11-28 12:42:30

标签: javascript unit-testing typescript collections jasmine

我有一个管理少量请求的类。因此请求被设置为集合。我已经这样做了,以避免编写冗长的switch / if else语句。

// Manager class
class makeManagerRequests() {
  private list = [];
  private createList(body) {
    this.list.push(body)
  }
  createEmployee(body) {
    this.createlist(body);
  }
  updateManager(body);
  deleteManager(body);
}

// Employee class
class makeEmployeeRequests() {

  private list = [];
  private createList(body) {
    this.list.push(body)
  }
  createEmployee(body) {
    this.createlist(body);
  }
  updateEmployee(body)
  deleteEmployee(body)
}

// Usage in a generic widget
class makeRequests() {

  requestMap = new Map();

  constructor(makeManagerRequests, makeEmployeeRequests) {

  }

  createRequestMap() {
    requestMap.set('createManager', this.makeManagerRequest.createManager.bind(this));
    requestMap.set('updateManager', this.makeManagerRequest.updateManager.bind(this));
    requestMap.set('deleteManager', this.makeManagerRequest.deleteManager.bind(this));
    requestMap.set('createEmployee', this.makeManagerRequest.createEmployee.bind(this));
    requestMap.set('updateEmployee', this.makeManagerRequest.updateEmployee.bind(this));
    requestMap.set('deleteEmployee', this.makeManagerRequest.deleteEmployee.bind(this));
  }

  makeRequest(data) {
    let req = requestMap.get(data.requestType);
    req(data.body)
  }

}

这本身就有效。

我注意到的第一件事是关键字"这个"使用来自" service"的get map时改变范围到"小部件"这样createlist()变得不确定。但如果我只是在没有绑定的情况下这样做就可以了。

  // I can test this with mocking the makeManagerRequest
  makeRequest(data) {
    this.makeManagerRequest.updateEmployee(body)        
  }

使用地图时我需要.bind(this)。不知道为什么"这个"更改?我创建的问题是当我尝试测试和模拟服务并监视服务时。我得到间谍从未被召唤过。所以我认为在创建地图时绑定创建新函数会发生什么。所以我无法窥探

spyOn(MockMakeManagerRequest, 'updateEmployee')

所以我试图弄清楚函数本身是如何存储在Map()中的。我正在寻找这个集合的技术含义以及我如何使这项工作能够实现这一目标。

这实际上是在Angular 2 app中使用的。但我不认为这会产生很大的不同,因为我试图计算/测试函数在Map()中存储为值时会发生什么;

1 个答案:

答案 0 :(得分:0)

Map中存储的内容是函数引用,仅此而已。您遇到的this问题与Map无关(除了它使用函数引用),它只是函数和this在JavaScript中的工作方式。我们来看一个更简单的例子:

class Example {
  constructor(message) {
    this.message = message;
  }
  method() {
    console.log(this.message);
  }
}
const c = new Example("Hi");
c.method(); // "Hi"
const f = c.method;
f();        // Error: Cannot read property 'message' of undefined

调用method时,如何调用它确定this是什么:如果我们使用从c获取它的表达式来调用它,然后在调用它期间this将具有值c。但如果我们不这样做,通常不会,它会有其他价值。

我意识到你问为什么this是错的,而不是如何解决它,但解释了为什么它是错的,这里有三种解决方案:

  1. Function#bind通过创建一个函数来解决这个问题,该函数在调用时调用原始文件并将this设置为特定值。

  2. 另一种解决方案是使用箭头函数作为包装器:

    requestMap.set('createManager', (...args) => this.makeManagerRequest.createManager(...args));
    

    箭头函数根据它们的调用方式设置this,它们关闭 this就像关闭范围内变量。因为我们在createRequestMap的调用中定义了它们,其中this是我们想要使用的对象,箭头关闭this并且我们很好。

    < / LI>
  3. 另一种选择是更改使用函数引用的调用:

    makeRequest(data) {
      let req = requestMap.get(data.requestType);
      req.call(this, data.body);
    // --^^^^^^^^^^^^
    }
    

    在那里,我们在调用this期间明确说出了我们想要req的内容。