0

Earlier today I got some simple code to work allowing an image to slide over on mouse over, and decided to try to turn that into a class so I could instantiate it. However, I'm running into some problems.

init() is called on window load, which sets up shifttabout() as a function to be called upon mousing over the image. However, when shifttabout() is called, I get the following error: "this.movetabout is not a function." How can this be?

   <script type="text/javascript">

        function SlidingTab(img)
        {
            this.self = this;

            this.outtimer;
            this.intimer;

            this.left = 0;
            this.interval = 20;
            this.animatingout = false;
            this.animatingin = false;
            this.increment = 10;
            this.extenddist = 100;
            this.imgobj = img;


            this.movetabout = function(){
                alert("moveout");
                this.animatingout = true;
                this.left = parseInt(this.imgobj.style.left);

                if(this.left != this.extenddist)
                {
                    this.imgobj.style.left = this.left + this.increment + 'px';

                    this.self = this;
                    this.outtimer = setTimeout(this.self.movetabout, this.interval);
                }
                else
                {
                    this.animatingout = false;
                }
            };

            this.shifttabout = function(){
                alert("shiftout");
                if(this.animatingin)
                {
                    this.animatingin = false;
                    clearTimeout(this.intimer);
                }
                if(!this.animatingout)
                {
                    this.movetabout();
                }   
            }

            this.init = function(){
                this.imgobj.style.position = 'relative';
                this.imgobj.style.left = '0px';

                this.self = this;

                this.imgobj.onmouseover=this.self.shifttabout;
            }
        }

        function init(){
            var img1 = document.getElementById("tab1");
            var tab1 = new SlidingTab(img1);
            tab1.init();
        }

        window.onload = init;

    </script>

Presumably I am setting up the onmouseover function incorrectly somehow, since all class variables appear to be undefined or otherwise messed up in shifttabout() when it is called by mouse hover, but not when it is called directly via init().

Curmudgeon
  • 194
  • 10
  • One question, why are you using `this.self = this;`? Just as a side note, this creates a circular reference to the object, which can now never be garbage collected (probably not a huge perf issue, but it creates an arbitrary memory leak). Also, just paradigmatically, it's strange that you would create a property of the object that refers directly to itself... – Josh Beam Aug 03 '15 at 21:25
  • @JoshBeam If circular references prevent the GC from cleaning it, it's a bug in the GC. – Barmar Aug 03 '15 at 21:30
  • @Barmar, thus is the nature of JavaScript garbage collection. Knowing that, there's no need to create unnecessary circular references. Either way, I see no conceivable reason why you would ever need to do `this.self = this`. A strange pattern regardless of whether or not JS's GC isn't optimal. – Josh Beam Aug 03 '15 at 21:31
  • @JoshBeam http://stackoverflow.com/questions/7347203/circular-references-in-javascript-garbage-collector – Barmar Aug 03 '15 at 21:33
  • @Barmar, right, good post, thanks. I think my main point is more about this part of my original post: "Also, just paradigmatically, it's strange that you would create a property of the object that refers directly to itself." – Josh Beam Aug 03 '15 at 21:35
  • 1
    Yeah, he might be confusing it with the need to create a closure variable `var self = this`. http://stackoverflow.com/questions/962033/what-underlies-this-javascript-idiom-var-self-this – Barmar Aug 03 '15 at 21:40
  • @Barmar, agreed (or, as the current top answer points out, using `Function.prototype.bind`). – Josh Beam Aug 03 '15 at 21:44
  • @Barmar I was indeed confusing it with creating a closure variable. Just a remnant of my attempts to get my code to work! – Curmudgeon Aug 04 '15 at 12:51

2 Answers2

2

your problem looks to be caused by these lines. Youre on the right track, in that you need to be properly setting the context of your function.

this.self = this;

this.imgobj.onmouseover=this.self.shifttabout;

change it to the following should properly set the context

this.imgobj.onmouseover=this.shifttabout.bind(this);

#bind(this) sets the scope of this inside the function to the input you pass it (in this case its the current scope)

Barmar
  • 596,455
  • 48
  • 393
  • 495
PhilVarg
  • 4,553
  • 2
  • 17
  • 34
  • Thanks -- this really helped! I also had to add a call to #bind(this) when setting the timeout in order for my code to work 100%, but this helped lead me there. Cheers ^_^ – Curmudgeon Aug 04 '15 at 12:49
0

The this you're using in the shifttabout refers to the shifttabout this - not the SlidingTab this.

You should pass the vars needed from outside shifttabout into it to use them properly.

Hope that helps.

itamar
  • 3,506
  • 3
  • 31
  • 55