【问题标题】:super method undefined in class declaration类声明中未定义的超级方法
【发布时间】:2018-11-01 17:22:07
【问题描述】:

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 数据存储在数据库中。因此,我第二次尝试使用new 关键字创建SearchResult 的实例,如下所示:

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 以访问Array 上的splice 方法。但是,这再次失败,抛出与以前相同的错误:

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

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


更新 2

在将类方法更新为shift 而不是splice 后,该方法现在可以正常工作而不会出现错误。我的问题现在得到了有效解决,但是我仍然希望了解super1 调用的问题与splice 有关。为什么这两个数组方法在这种情况下会有不同的表现。

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

【问题讨论】:

  • 你确定这个错误真的是super()调用引起的吗?还是只是“在那一行”?

标签: javascript class new-operator extends super


【解决方案1】:

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

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

 SearchResult = function() { undefined(); }

但我猜你不会那样做。

但是错误是从哪里来的呢?

那一行发生了两件事:

 super(...resultArray);

一个是super() 调用,另一个是resultArray 的传播,它将创建和消耗resultArray 的迭代器,它几乎等于:

 resultArray[Symbol.iterator]()

如果迭代器不存在(因为你不小心将一个非数组传递给构造函数)它会失败,说迭代器不能被调用:

 var resultArray = {};

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

【讨论】:

  • 啊,谢谢你说得有道理!正如您在评论中所说,我不确定它是 super 只是错误所在的行,所以它可能是传播。我会检查以确保我实际上传递了一个数组。
  • 我已经测试了创建第二个实例时传递的resultArray 数据,你说得对,这是问题所在。我传递了正确的数据,但是数据类型错误。它是一个带有数字键的常规对象,而不是一个实际的数组(记录它返回这个{ '0': {...}, '1': {...} } 而不是这个[{...}, {...}])。我现在只需要确定数据类型发生变化的原因以及如何解决它。
  • 我根据您的评论解决了最初的super 呼叫/传播问题,但是一旦创建了类实例,就会立即重复同样的问题。我在上面添加了详细信息的更新。
  • @josh 实际上这是一个全新的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-10
相关资源
最近更新 更多