1

I'm a bit confused on the result I'm getting when calling the 'this' variable inside in object constructor.

function Slider(tag){
    this.tag = document.querySelector(tag),
    this.start = function(){
        return this.interval;
    },
    this.interval = setInterval(function(){
        console.log(this.tag); //undefined
        console.log(this); //window object
    }, 2000)
}
var route ={
    init:function(){        
        mySlide = new Slider('slider');
        mySlide.start();
    }
}
document.addEventListener('DOMContentLoaded', route.init);

I'm logging tag console.log(this.tag) however it's returning undefined and when logging the this variable inside console.log(this) it refers to the window object.

Here is a Demo

Question: Why isn't console.log(this.tag) returning the selected element?

2
  • 1
    Callback functions don't inherit this from the surrounding scope. You can either use bind or assign a variable var self = this; in the surrounding scope. Commented Nov 9, 2016 at 20:18
  • 2
    Lexical Scoping, read up on this. Commented Nov 9, 2016 at 20:22

2 Answers 2

2

This is because when you pass a callback function to setInterval, it's called in the global scope. That's why this is window.

You can use Function.bind() to set the context of the function to your this object and make it work as you want.

this.interval = setInterval(function(){
    console.log(this.tag);
}.bind(this), 2000);

Also, I just want to point out that mySlide.start(); does nothing. When you call new Slider('slider'), that's when your interval is set. Your mySlide.start(); just returns the intervalID (which is only used for clearInterval()). Actually since you are not even using the return value of mySlide.start();, calling it is useless.

UPDATE: Another solution is to use var self = this; in your constructor function and then use self inside setInterval():

function Slider(tag){
    var self = this;

    this.tag = document.querySelector(tag),
    this.interval = setInterval(function(){
        console.log(self.tag);
    }, 2000);
}

UPDATE: If you are on a browser that supports "arrow functions", then you can do this:

this.interval = setInterval(() => {
    console.log(this.tag);
}, 2000);
Sign up to request clarification or add additional context in comments.

9 Comments

Ahhh I nice yeah bind works, was just going to say that... so I want to be able to clear the interval, but need to set the setInterval to a variable to be able to clear it you know. Is there a better approach you would use to .start() and .clear()?
@JordanDavis: I would have .start() be the one to call setInterval(). Have .start() do this.interval = setInterval(function(){...});, that way you can have a .clear() do clearInterval(this.interval);. Right now, your .start() doesn't actually start anything.
Awesome your the man! Is that a typical/standard approach to use the bind method?
@JordanDavis: It's one approach, yeah. It's normal. Another approach is to do something like var self = this; at the very top of your Slider function. Then use self.tag inside your setInterval().
Oh no I know the scope changes, between the two for this variable. I just typically don't do this kind of object creation this way, so just little confused.
|
1

The scope of the anonymous function in the setInterval is the Window. If you want it to be the Slider instance, you should bind it first.

function Slider(tag){
this.tag = document.querySelector(tag),
this.start = function(){
    return this.interval;
},
this.interval = setInterval(function(){
    console.log(this.tag); //undefined
    console.log(this); //window object
}.bind(this), 2000)
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.