类声明中未定义的超级方法

时间:2018-11-01 17:22:07

标签: javascript class new-operator extends super

TL; DR -我的类声明中的super关键字有时(但并非总是)未定义。如何/为什么?

我有以下扩展了Array的类声明,该类声明用于来自API的搜索结果数据:

class SearchResult extends Array {
  constructor(resultArray) {
    super(...resultArray);
  }

  static createFromApiData(apiData) {
    const resultArray = apiData.filter(...).map(...);
    return new SearchResult(resultArray);
  }

  ...otherMethods

}

在我的应用中,这是在收到来自API的响应后立即调用的,如下所示:

apiCall().then((res) => {
  const searchResults = SearchResult.createFromApiData(res.data);
});

使用此静态方法创建新的SearchResult实例可以正常工作,并返回我想要的内容。

但是,稍后在我的应用程序中,我需要再次创建SearchResult实例,这一次无需进行API调用,因为我已经将resultArray数据存储在数据库中。因此,第二次尝试使用SearchResult关键字创建new的实例,如下所示:

const searchResults = new SearchResult(resultArray);

这次,使用new关键字,实例创建失败并引发以下错误:

TypeError: undefined is not a function at new SearchResult

在这种情况下,我知道undefined是指super关键字,但是我不明白为什么会这样?在这两种情况下,实例创建行为如何变化?我该如何解决?


更新

我已经进一步调查,发现了以下内容。最初的问题是由于我将自定义SearchResult类实例保存到数据库( dynamodb )引起的。尽管SearchResult扩展了数组,但 ddb 将其保存为基本对象,因此从数据库中检索数据时,它是基本对象,而不是数组形式。当我尝试在super函数内部传播对象时,这引发了错误。

我通过将类实例保存到 ddb 时将类实例散布到新数组中来解决了这个问题:

db.save([...searchResults]);

这会在数据库撤回后返回一个数组,并且可以成功地在super调用中传播。

但是,这导致了一个新问题。创建新的SearchResult实例后,立即在其上调用以下自定义方法:

nextItem() {
  this.splice(0, 1);
  return this[0];
}

然后,此方法再次调用super以访问splice上的Array方法。但是,这再次引发与以前相同的错误:

{
  "errorMessage": "undefined is not a function",
  "errorType": "TypeError",
  "stackTrace": [
    "new SearchResult",
    "SearchResult.splice",
    "SearchResult.nextRecipe"
}

再次指的是super内部的传播操作。这次super被传递了数字1作为唯一参数。 1是哪里来的,我该如何解决?


更新2

在将类方法更新为我们的shift而不是splice之后,该方法现在可以正常工作而不会出错。现在,我的问题已得到有效解决,但是,对于使用super调用1所引起的splice问题,我还是深表感谢。为什么这两个数组方法在这种情况下会有不同的表现。

nextItem() {
  return this.shift();
}

1 个答案:

答案 0 :(得分:1)

  

我知道在这种情况下undefined指的是super关键字,但我不明白为什么是这种情况?

可能不是。 super指向该类的内部不可更改的[[HomeObject]]属性,该属性在声明该类时设置,您不能修改它,只能重写该类本身,例如:

 SearchResult = function() { undefined(); }

但是我想你不会那样做。

但是错误从哪里来?

那一行发生了两件事:

 super(...resultArray);

一个是super()调用,另一个是resultArray的扩展,这将创建并使用resultArray的迭代器,该迭代器几乎不等于:

 resultArray[Symbol.iterator]()

,如果迭代器不存在(因为您不小心将非数组传递给了构造函数),它将失败,表示无法调用该迭代器:

 var resultArray = {};

 resultArray[Symbol.iterator]()
 // equals:
 undefined()