Search code examples
javascriptxmlhttprequestprototype

Understanding call() Function and Objects


I have a modular JS project that I was given to tweak. It uses prototype inheritance as opposed to classes. Here is the code in question:

Constructor in hgManager.js:

export function HGManager() {
    this.USER_ID = getURLParameter( "usr" ),
    this.GAME_ID = getURLParameter( "game" )
};

getData() in hgManager.js:

getData: function(a, b) {
        var c = this.API + "records/" + this.USER_ID + "/" + this.GAME_ID;
        this.xhrLoad( "GET", c, a, b )
    },

xhrLoad() in hgManager.js:

xhrLoad: function(a, b, c, d, e) {

        var f = new XMLHttpRequest;
        f.open(a, b, true), 
        e && f.setRequestHeader("Content-type", "application/json");

        var g = this;

        f.onload = function() {
            if (4 == f.readyState && f.status >= 400 && f.status <= 599) {                     return d.call(g, f);
            }

            else { 
                var a = JSON.parse( f.responseText ).response;

                return c.call(g, a, f)    
            }

        },

        f.onerror = function() {
            return d.call(g, f)
        },


        e ? f.send( JSON.stringify( e ) ) : f.send() 
    }

A function that calls hgManager.getData():

loadPlayerData: function() { 
        var a = this;
        this.game.hgManager.getData(
            function( c ) { //param 1
                if ( null === c ) { 
                    return void console.log( "DataManager: Invalid response." ); //if there is no playerData
                }

                var d = JSON.parse( c.record );
                void 0 === d || null === d || void 0 === d.selectedCharacter ? (console.log("DataManager: No data on backend, looking for data on local storage."), d = a._getLocalStorageData(), null !== d ? (console.log("DataManager: Data on localstorage found. Saving this to backend."), a.game.playerData = d) : console.log("DataManager: No data on localstorage. Saving default data to backend."), a.savePlayerData()) : console.log("DataManager: Data loaded from backend.");
                var e = new Date,
                    f = e.getFullYear() + "-" + e.getMonth();
                d.lastMonthPlayed != f && (d.lastMonthPlayed = f, d.loyaltyPoints = [], console.log("DataManager: New month, reset loyalty points.")),
                a.game.playerData = d,
                a.game.hasShownLoyaltyMessage = a.game.playerData.loyaltyPoints.length > 0,
                a.game.hasShownPortalMessage = 9 == a.game.playerData.portalPieces.length
            },

            function() { //param 2
                console.log("DataManager: Error loading user data"), 
                data = a._getLocalStorageData(), 
                null !== data ? (console.log("DataManager: Data on localstorage found."), a.game.playerData = data) : console.log("DataManager: No data on localstorage.") 
            }
        ) 
    },

The code that is throwing me off is return c.call(g, a, f) in xhrLoad(), and the corresponding first parameter function of loadPlayerData().

  • Where does the parameter 'c' in this.game.hgManager.getData(function( c ) { come from? It is clearly not defined in this scope, so I imagine it is a result of the call()?

  • How does loadPlayerData() read what appears to be undefined in the scope?

  • Given the function this.game.hgManager.getData( function(c), why would we reassign the parent object and call getData()? What is the intent?


Solution

  • It's quite difficult to deal with variables like a, b, c especially when they mean different things in different scopes.

    But let's try to follow code and rename args to add some sence:

    xhrLoad: function(method, target, callbackSuccess, callbackError, e/* idk what is it*/) {}
    
    getData: function(callbackSuccess, callbackError) {
            var target = this.API + "records/" + this.USER_ID + "/" + this.GAME_ID;
            this.xhrLoad( "GET", target, callbackSuccess, callbackError )
        },
    
    this.game.hgManager.getData(
            function( response ) { //param 1 callbackSucess
                    if ( null === response ) { 
                        return void console.log( "DataManager: Invalid response." ); //if there is no playerData
                    }
    
    
                },
            function() { //param 2 callbackError
              //
            }
    

    Now it's easier to understand.

    getData() accepts as arguments two callback functions - one for successful response and one for error. First one must accept response as argument. It's your c from this.game.hgManager.getData(function( c ) { and it's defined right here. Since it's a function's argument, there is no need to define it in global scope.

    And seems, that there is nothing to do with classes here. It's all about passing functions as arguments.