Variable scope in Javascript Object

2019-07-15 12:44发布

问题:

I'm discovering the concept of "objects" in JavaScript. I'm making an RSS Parser, and I have an error (commented).

function MyParser (feed_url) {  // Construct
    "use strict";
    this.feedUrl = feed_url;
    this.pubArray = [];

    if (typeof (this.init_ok) == 'undefined') {
        MyParser.prototype.parse = function () {
        "use strict";
        var thisObj = this;
        $.get(this.feedUrl, function (data, textStatus, jqXHR) {
            if (textStatus == 'success') {
                var xml = jqXHR.responseXML,
                    //lastBuildDate = new Date($(xml).find('lastBuildDate').text());
                    items = $(xml).find('item');
                items.each(function () {
                    var pubSingle = thisObj.makeObj($(this).find('pubDate').text(),
                                                    $(this).find('link').text(),
                                                    $(this).find('title').text(),
                                                    $(this).find('description').text(),
                                                    $(this).find('encoded').text(),
                                                    $(this).find('commentRss').text(),
                                                    $(this).find('comments').last().text());
                    thisObj.pubArray.push(pubSingle);
                });
                console.log(thisObj.pubArray); // OK
            }
        }, 'xml');
        console.log(this.pubArray); // Empty
        return (this.pubArray);
    };

    MyParser.prototype.makeObj = function (pubDate, pubLink, pubTitle, pubDesc, pubContent, pubComCount, pubComLink) {
        "use strict";
        var pubSingle = {};
        pubSingle.pubDate = new Date(pubDate);
        pubSingle.pubLink = pubLink;
        pubSingle.pubTitle = pubTitle;
        pubSingle.pubDesc = pubDesc;
        pubSingle.pubContent = pubContent;
        pubSingle.pubComCount = pubComCount;
        pubSingle.pubComLink = pubComLink;
        return (pubSingle);
    };
}
this.init_ok = true;
}

If you look at the console.log(), you'll see that the line // OK is outputting my array correctly.

But later, when returning from $.get, my array is empty.

Does anybody have an idea why, and how to correct that please?

回答1:

This is not a problem with variable-scope. The problem here is that you're working with asynchronous flow and you're not thinking correctly the flow.

Let me explain:

When you do your .get, you fire a parallel asynchronous process that will request information from the browser, but your main program's flow keeps going, so when you get to your "return" statement, your array has not been filled yet with the response from your get method.

You should use your array from inside the get callback and not outside of it, since you can't guarantee that the array will have the information you need.

Does it make any sense?

Let me know!

Further explanation

According to your comments, you're still doing something like this:

var results = MyParser(feed_url); //code that uses results.pubArray

And you cannot do that. Even though you're setting your "pubArray" inside your .get callback, you're trying to use pubArray right after you called MyParser and that's before the .get callback is called. What you have to do, is call your next step on your program's logic from within the .get callback... that's the only way you can be sure that the pubArray is filled with proper data.

I hope that makes it clearer.



回答2:

This is because your line

 console.log(this.pubArray); // Empty

is being called directly after you issue your Ajax request; it hasn't had time to fetch the data yet. The line

console.log(thisObj.pubArray); // OK

is being called inside the Ajax callback, by which time the data has been fetched.



回答3:

Thank you all, and particulary @Deleteman .

Here is what I did:

$.get(this.feedUrl, 'xml').success(function () {
    thisObj.handleAjax(arguments[0], arguments[1], arguments[2]);
    $(document).trigger('MyParserDone');
}).error(function () {
    $(document).trigger('MyParserFailed');
});

Then, when i enter "HandleAjax", i'm back in my object context, so "this" refers to my object and the right properties. The only "problem" is that I have to set a listener (MyParserDone) to make sure the parsing is finished.