Потеря доступа к функциям внутри класса JS при выполнении обратного вызова

Я работаю над приложением TVML/TVJS и столкнулся с проблемой при работе с классами в Javascript.

Мой начальный файл application.js вызывает функцию

resourceLoader = new ResourceLoader();
resourceLoader.getHomeScreen();

У меня есть отдельный файл с именем ResourceLoader.js со следующим:

class ResourceLoader {

getHomeScreen() {
    var homeData = BASEURL + "/home.json";
    var homeTemplate = BASEURL + "/home.tvml";

    this.getRemoteJSON(homeData, homeTemplate, this._jsonLoaded);
}

_jsonLoaded(template, jsonString) {
    var parsedJSON = JSON.parse(jsonString);
    this.getRemoteXMLFile(template, parsedJSON);
}

getRemoteJSON(file, template, callback) {
    var xhr = new XMLHttpRequest();
    xhr.responseType = "text";
    xhr.addEventListener("load", function() {
        callback(template, xhr.responseText);
    }, false);
    xhr.open("GET", file, true);
    xhr.send();
}

getRemoteXMLFile(template, json) {
    var xhr = new XMLHttpRequest();
    xhr.responseType = "xml";
    xhr.addEventListener("load", function() {
        loadRemoteFile(xhr.responseText, json);
    }, false);
    xhr.open("GET", template, true);
    xhr.send();
}

}

(BASEURL — это глобальная переменная, определенная в application.js)

Все работает нормально в начале. getHomeScreen() вызывается, ему удается вызвать getRemoteJSON() и передать _jsonLoaded() в качестве обратного вызова. getRemoteJSON выполняет вызов AJAX, а затем выполняет обратный вызов. Здесь возникает проблема. Оказавшись внутри _jsonLoaded, «это» становится неопределенным, поэтому, когда я вызываю this.getRemoteXMLFile, я получаю сообщение об ошибке «неопределенное не является объектом (оценка« this.getRemoteXMLFile »)»

Почему «это» работало в getHomeScreen(), но не в _jsonLoaded()? Как я могу получить доступ к моей функции getRemoteXMLFile из _jsonLoaded()?

Спасибо за любую помощь.


person cesarcarlos    schedule 15.01.2017    source источник


Ответы (2)


Это потому, что обратный вызов не является функцией.

Хорошим решением будет использование обещаний ES6.

Вот пример получения данных с использованием AJAX с обещанием

getJson(url) {
    return new Promise(
        (resolve, reject) => {
            this.get(url).then(
                (value) => {
                    resolve(JSON.parse(value));
                },
                function (reason) {
                    console.error(reason);
                    reject(new Error(reason));
                }
            )
        }
    )
}

И как это назвать

getJson('http://jsonplaceholder.typicode.com/posts/1').then(
    (value) => {
        console.log(value);
    },
    function (reason) {
        console.error(reason);
    }
);
person Ariel    schedule 15.01.2017

Почему «это» работало в getHomeScreen(), но не в _jsonLoaded()? Как я могу получить доступ к моей функции getRemoteXMLFile из _jsonLoaded()?

Технически это не относится к приложению TVML, а скорее к общему вопросу JS, поэтому позвольте мне ответить this (без каламбура) в свете JavaScript.

Когда вы вызываете getHomeScreen, вы вызываете его для экземпляра объекта resourceLoader.getHomeScreen(), и, следовательно, контекст this сохраняется. Но когда вы передаете функцию _jsonLoaded в качестве аргумента обратного вызова функции и делаете callback(template, xhr.responseText), контекст объекта теряется.

Недавно введенное ключевое слово JavaScript class может сбивать с толку тех, кто знаком с чистым ООП-языком, поскольку это не объектно-ориентированное наследование, а просто синтаксический сахар для векового прототипного наследования в JavaScript. Поэтому, если вы принадлежите к одной и той же группе, рекомендуется понимать различия и подвохи.

Сказав это, одним прямым и простым решением вашей непосредственной проблемы является bind контекст this всякий раз, когда вы передаете функцию как обратный вызов.

this.getRemoteJSON(homeData, homeTemplate, this._jsonLoaded.bind(this));

Примечание. Пробовали ли вы использовать платформу atvjs для создания приложений TVML? Он позволяет создавать и быстро создавать прототипы приложений без особого шума, абстрагируя основные проблемы и сложности обычного приложения TVML.

person eMAD    schedule 29.06.2017