ES6: «TyperError: X не является функцией»

Я пытаюсь добавить функцию в класс на своем сервере Express/Node, но постоянно получаю TypeError: req.session.user.bills[0].getFormattedDueDate is not a function. У меня есть другие классы, чьи функции-члены работают, в том числе в том же методе, который выдает эту ошибку. Я проверил тип объектов в req.session.user.bills, и это был object. Проект построен с помощью Webpack и Babel.

Если я возьму все свойства из req.session.user.bills[0] и помещу их в новый объект, то функции будут работать. Поток данных для этого объекта работает следующим образом. Имя основного файла server2.js.

  1. Пользователь входит в систему, нажимая и конечную точку в server2.js.
  2. Имя объекта userDao получает пользователя из базы данных и возвращает объект User с массивом Bills. И UserDao, и User стоят required вверху server2.js.
  3. Другая конечная точка используется для отображения счетов. Это передает объект User в файл EJS. Именно здесь я пытаюсь использовать функцию, и она не работает.

server.js:

const User = require('babel-loader!./src/model/user.js');
const UserDao = require('babel-loader!./src/model/userDao.js');
const Bill = require('babel-loader!./src/model/bill.js');

const userDao = new UserDao(pool);
...
app.all('/bills', function(req, res) {
    const temp1 = req.session.user.bills[0].getFormattedDueDate();
    res.render('bills.ejs', {
        URL: config.URL,
        user: req.session.user
    })
});

Но если я создаю новый объект, он работает:

app.all('/bills', function(req, res) {
    const temp = new Bill(
        req.session.user.bills[0].id, 
        req.session.user.bills[0].userId, 
        req.session.user.bills[0].periodId, 
        req.session.user.bills[0].accountId, 
        null, 
        req.session.user.bills[0].name, 
        req.session.user.bills[0].amount, 
        req.session.user.bills[0].autoPay, 
        req.session.user.bills[0].weekDay, 
        req.session.user.bills[0].dueDate, 
        req.session.user.bills[0].dueDate2, 
        req.session.user.bills[0].paid
    );
    const temp1 = temp.getFormattedDueDate();
    res.render('bills.ejs', {
        URL: config.URL,
        user: req.session.user
    })
});

userDao.js:

//Lots of other data is put in user...
//Bills
for (let i = 0; i < rows[BILLS_INDEX].length; i++) {
    user.bills.push(new Bill(
        rows[BILLS_INDEX][i].id,
        rows[BILLS_INDEX][i].userId,
        rows[BILLS_INDEX][i].periodId,
        rows[BILLS_INDEX][i].accountId,
        new Tag(rows[BILLS_INDEX][i].tagId, rows[BILLS_INDEX][i].userId, rows[BILLS_INDEX][i].name),
        rows[BILLS_INDEX][i].name,
        rows[BILLS_INDEX][i].amount,
        rows[BILLS_INDEX][i].autoPay === 1,
        rows[BILLS_INDEX][i].weekDay === 1,
        rows[BILLS_INDEX][i].startDate,
        rows[BILLS_INDEX][i].startDate2,
        rows[BILLS_INDEX][i].paid === 1
    ));
}

resolve(user);

user.js:

module.exports = class User {
    constructor(id, firstName, lastName, imageUrl, email, tags, items, budgetItems, piggyBanks, bills) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.imageUrl = imageUrl;
        this.email = email;
        this.tags = tags || new Array();
        this.items = items || new Array();
        this.budgetItems = budgetItems || new Array();
        this.piggyBanks = piggyBanks || new Array();
        this.bills = bills || new Array();
    }
}

bill.js:

const moment = require('moment');

module.exports = class Bill {
    constructor(pId, pUserId, pPeriodId, pAccountId, pTag, pName, pAmount, pAutoPay, pWeekDay, pdueDate, pdueDate2, pPaid) {
        this.id = pId;
        this.userId = pUserId,
        this.periodId = pPeriodId,
        this.accountId = pAccountId,
        this.tag = pTag,
        this.name = pName,
        this.amount = pAmount,
        this.autoPay = pAutoPay,
        this.weekDay = pWeekDay,
        this.dueDate = pdueDate,
        this.dueDate2 = pdueDate2,
        this.paid = pPaid
    }

    getFormattedDueDate() {
        return moment(this.dueDate).format('MMM DD, YYYY');
    }

    getFormattedDueDate2() {
        return moment(this.dueDate2).format('MMM DD, YYYY');
    }
}

Я ожидал, что метод сработает, так как методы в userDao.js работают, но я получаю ошибку неопределенного метода.

Обновлено: Я проверил req.session.user.bills[0] instanceof Bill и вернул ложь.

Ты никогда не звонишь getFormattedDate

VLAZ 07.04.2019 19:55

Как вы ставите req.session.user.bills в сессии? Это не похоже на Bill объект. Вы используете JSON.stringify -> JSON.parse?

VLAZ 07.04.2019 19:57

Я делаю это в server2.js, когда создаю экземпляр переменной temp1.

silvertiger 07.04.2019 19:58

Когда пользователь входит в систему, я устанавливаю req.session.user = user после получения всей его информации.

silvertiger 07.04.2019 19:59

Вы звоните getFormattedDueDate не getFormattedDate

VLAZ 07.04.2019 19:59

Вы проверили, действительно ли req.session.user.bills содержит Bill объекты? Как я уже сказал, не похоже. Я подозреваю, что они были сериализованы -> десериализованы, что означает, что все функции удалены.

VLAZ 07.04.2019 20:00

Это была опечатка в ошибке, извините. Я отредактировал его, чтобы сделать его правильным.

silvertiger 07.04.2019 20:02

Я забыл упомянуть, что проверил тип req.session.user.bills[i], и это было object. Новый мастер вопросов меня запутал :)

silvertiger 07.04.2019 20:03

Хорошо... как вы проверили тип? Потому что typeof просто скажет вам object для любого объекта. Вы можете проверить bills[0] instanceof Bill, который скажет вам, является ли это счетом или нет.

VLAZ 07.04.2019 20:06

А, я использовал typeof. Я проверю instanceof.

silvertiger 07.04.2019 20:10

Он вернул ложь.

silvertiger 07.04.2019 20:14

Как использовать методы без повторного создания сотни объектов в req.session.user?

silvertiger 07.04.2019 20:29
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
12
455
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Когда вы сохраняете объект в session, он сериализуется как JSON. И когда вы его извлекаете, он снова анализируется как простой объект. Таким образом, любая исходная информация о прототипе теряется в этом процессе. Как указано в документации модуль экспресс-сессии:

To store or access session data, simply use the request property req.session, which is (generally) serialized as JSON by the store [...]

Чтобы восстановить информацию о прототипе, вы можете сделать:

req.session.user.bills.forEach(bill => Object.setPrototypeOf(bill, Bill.prototype));

И тогда это должно работать:

const temp1 = req.session.user.bills[0].getFormattedDueDate();

В качестве альтернативы, если вы просто хотите иметь возможность вызвать метод один раз, вы можете использовать .call:

const temp1 = Bill.prototype.getFormattedDueDate.call(req.session.user.bills[0]);

Другие вопросы по теме