-2

I'm running through a HTML5 game tutorial and came across the function below. Can anyone explain how this function works?

 var super_update = self.update;
    self.update = function(){
            super_update();
            self.attackCounter += self.atkSpd;
    }

I'm not sure why you would need this type of function, the logic seems confusing.

Why would we need a variable called super_update?

//------------------------- Full code -------------------//


Player = function(){
        var self = Actor('player','myId',50,40,30,5,20,20,'green',10,1);

        self.updatePosition = function(){
                if(self.pressingRight)
                        self.x += 10;
                if(self.pressingLeft)
                        self.x -= 10;  
                if(self.pressingDown)
                        self.y += 10;  
                if(self.pressingUp)
                        self.y -= 10;  


        var super_update = self.update;
        self.update = function(){
                super_update();
                if(self.hp <= 0){
                        var timeSurvived = Date.now() - timeWhenGameStarted;           
                        console.log("You lost! You survived for " + timeSurvived + " ms.");            
                        startNewGame();
                }
        }

        self.pressingDown = false;
        self.pressingUp = false;
        self.pressingLeft = false;
        self.pressingRight = false;
        return self;

}

Entity = function(type,id,x,y,spdX,spdY,width,height,color){
        var self = {
                type:type,
                id:id,
                x:x,
                y:y,
                spdX:spdX,
                spdY:spdY,
                width:width,
                height:height,
                color:color,
        };
        self.update = function(){
                self.updatePosition();
                self.draw();
        }
        self.draw = function(){
                ctx.save();
                ctx.fillStyle = self.color;
                ctx.fillRect(self.x-self.width/2,self.y-self.height/2,self.width,self.height);
                ctx.restore();
        }
        self.getDistance = function(entity2){   //return distance (number)
                var vx = self.x - entity2.x;
                var vy = self.y - entity2.y;
                return Math.sqrt(vx*vx+vy*vy);
        }

        self.updatePosition = function(){
                self.x += self.spdX;
                self.y += self.spdY;

                if(self.x < 0 || self.x > WIDTH){
                        self.spdX = -self.spdX;
                }
                if(self.y < 0 || self.y > HEIGHT){
                        self.spdY = -self.spdY;
                }
        }

        return self;
}



Actor = function(type,id,x,y,spdX,spdY,width,height,color,hp,atkSpd){
        var self = Entity(type,id,x,y,spdX,spdY,width,height,color);

        self.hp = hp;
        self.atkSpd = atkSpd;
        self.attackCounter = 0;
        self.aimAngle = 0;



        var super_update = self.update; // WHAT IS THIS FOR?
        self.update = function(){
                super_update();
                self.attackCounter += self.atkSpd;
        }


        self.performAttack = function(){
                if(self.attackCounter > 25){    //every 1 sec
                        self.attackCounter = 0;
                        generateBullet(self);
                }
        }



        return self;
}
stckpete
  • 571
  • 1
  • 4
  • 13

1 Answers1

0

First, you didn't link all the code. Chances are there's another line like this somewhere:

var self = this;
// Stuff...

// Code you posted.

As for how it works...

The linked snippet starts with var super_update = self.update; In JavaScript, this can be read as, "assign the contents of the property update of object self to the variable super_update.

The reason this works is because JavaScript is an object-oriented language! The next line, self.update = function () { functionbody }; is creating a function object with the given function body, and assigning it to the property update of object self.

Now, I'm sure you're asking yourself, "doesn't the order of the instructions matter?" In this case...the answer is 'yes, but with caveats'. Primitives like undefined/null, numbers, and booleans are all passed by value; objects and arrays are passed by something very much resembling reference*. As function objects are still objects, they are not passed by value, thus every time super_update is called, the contents of self.update as self.update existed at the time of the assignment will execute.

Now, this will not work for the reason @JaredSmith noted in the comments of the original question: there is a case of infinite recursion, or a method calling itself with no means of not doing so. You're assigning self.update to super_update, but calling self.update within super_update. Thus, this code will lock up the page it's executing on. This is not a good thing. I suggest removing the call to super_update inside of the self.update function.

Another reason I'm sure you didn't post all of the code, is that usually this sort of 'assign behavior' setup takes place within JavaScript frameworks such as three.js or angular...presumably, whatever the one it was that you were doing a tutorial on. And, that's the point of this code - to pass a configurable behavior to some predefined bit of code to get it to act in a custom way.

TL;DR: In JavaScript functions can be assigned to variables/properties and passed as parameters. You can use this to make existing code exhibit polymorphic behavior.

Super TL;DR: In JavaScript, functions are first-class citizens of the language.

Super-Duper TL;DR: This snippet:

var super_update = self.update;
self.update = function () {};

...Is what's called a closure; which means that super_update was assigned self.update as it existed at the time of the assignment. Closures are a useful topic you may want to read more on. (Thanks to @ankhzet in this answer's comments.)

*: The reason I say 'something very much resembling reference', is because JavaScript actually has no concept of passing something by reference/pointer - JavaScript is a high-level language, and thus does not deal with passing memory addresses, exactly. That occurs under the hood inside the JavaScript engine.

Andrew Gray
  • 3,756
  • 3
  • 39
  • 75
  • 1
    Super-Super TL;DR: self.update = function(){} acts ac `closure`, whitch captures the reference to `super_update`, no matter what it'll hold in future. – ankhzet Jan 17 '16 at 22:59
  • That is true, but this seems to be a novice programmer posting this question; I didn't want to over-burden this programmer who is clearly new to JavaScript, with the concept of closures. They're using them, but probably realize it now that we're talking about closures. ;) – Andrew Gray Jan 17 '16 at 23:01
  • Hi Andrew, I have uploaded the full code for review – stckpete Jan 18 '16 at 00:27