运行回调时无法访问 JS 类中的函数

Posted

技术标签:

【中文标题】运行回调时无法访问 JS 类中的函数【英文标题】:Losing access to functions within a JS class when running a callback 【发布时间】:2017-01-15 15:58:16 【问题描述】:

我正在开发一个 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”变为未定义,因此当我调用 this.getRemoteXMLFile 时,我收到错误消息“未定义不是对象(正在评估 'this.getRemoteXMLFile')”

为什么“this”在 getHomeScreen() 中有效,但在 _jsonLoaded() 中无效?如何从 _jsonLoaded() 访问我的 getRemoteXMLFile 函数?

感谢您的帮助。

【问题讨论】:

【参考方案1】:

那是因为回调不是一个函数。

一个好的解决方案是使用 ES6 Promises。

这是一个使用带有 Promise 的 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);
    
);

【讨论】:

【参考方案2】:

为什么“this”在 getHomeScreen() 中有效,但在 _jsonLoaded() 中无效?如何从 _jsonLoaded() 访问我的 getRemoteXMLFile 函数?

这在技术上并不特定于 TVML 应用程序,而是更多的一般 JS 问题,所以让我根据 JavaScript 回答 this(不是双关语)。

当您调用 getHomeScreen 时,您会在对象实例 resourceLoader.getHomeScreen() 上调用它,因此会保留 this 上下文。但是当你将_jsonLoaded 函数作为函数的回调参数传递并执行callback(template, xhr.responseText) 时,对象上下文就丢失了。

最近为具有纯 OOP 语言背景的人引入了 JavaScript class 关键字 might be confusing,因为它不是面向对象的继承,而仅仅是 JavaScript 中古老的原型继承的语法糖。因此,如果碰巧属于同一组,建议了解差异并gotchas。

话虽如此,当您将函数作为回调传递时,一个直接而简单的解决方案就是在bind this 上下文中处理您的直接问题陈述。

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

旁注:您是否尝试过 atvjs 框架来构建 TVML 应用程序?它可以让您在没有太多噪音的情况下构建和快速原型化应用程序,从而抽象出传统 TVML 应用程序的底层麻烦和复杂性。

【讨论】:

以上是关于运行回调时无法访问 JS 类中的函数的主要内容,如果未能解决你的问题,请参考以下文章

无法理解react.js中的处理事件[关闭]

Swift无法使用类型(实例)访问类中的静态变量

Jaxl 类基回调

我的函数不知何故无法访问其父闭包并且缺少变量。如何?

无法在回调函数中访问属性React

如何使用 node.js 运行时访问 Azure Function App 函数中的 multipart/form-data