супер метод не определен в объявлении класса - PullRequest
0 голосов
/ 01 ноября 2018

TL; DR - Супер-ключевое слово в моем объявлении класса иногда (но не всегда) не определено. Как / почему?

У меня есть следующее объявление класса, расширяющее 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, но я не могу понять, почему это так? Как может изменяться поведение создания экземпляра в этих двух случаях? Как я могу это исправить?


UPDATE

Я продолжил расследование и обнаружил следующее. Первоначальная проблема была вызвана тем, что я сохранял свой экземпляр класса SearchResult в базе данных ( dynamicodb ). Хотя 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 голосов
/ 01 ноября 2018

Я знаю, что неопределенное в этом контексте относится к ключевому слову super, но я не могу понять, почему это так?

Вероятно, нет. super относится к внутреннему неизменяемому свойству [[HomeObject]] класса, которое устанавливается при объявлении класса, вы не можете изменить его, вы можете переписать только сам класс, например ::

 SearchResult = function() { undefined(); }

Но я думаю, вы этого не делаете.

Но откуда берется ошибка?

Ну, в этой строке происходит две вещи:

 super(...resultArray);

Один - это вызов super(), а другой - распространение resultArray, которое создаст и использует итератор resultArray, который едва равен:

 resultArray[Symbol.iterator]()

и если итератор не существует (потому что вы случайно передали не массив в конструктор), он завершается ошибкой, говоря, что итератор не может быть вызван:

 var resultArray = {};

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