11

I've been reading Game Design with HTML5 and JavaScript and it introduced me to objects. So after reading the book and working on the projects I decided to take this new found knowledge and integrate objects in my own projects. So here's my question can or should objects call their own functions? For example:

var someObject = {
    start: function() {
        check();
    },
    check: function() {
        console.log("Check!");
    }
};

someObject.start();

The book did show an example with a timer that does this:

var timer = {
    start: function() {
        var self = this;
        window.setInterval(function(){self.tick();}, 1000);
    },
    tick: function() {
        console.log('tick!');
    }
};

In the example with timer object it makes a reference to self in order to call the internal function, so does this mean I should use self to call internal functions or is this the proper way to do this with objects? Or best practices? Thanks in advance.

var someObject = {
    start: function() {
        var self = this;
        self.check();
    },
    check: function() {
        console.log("Check!");
    }
};

someObject.start();
CodeEngie
  • 357
  • 2
  • 4
  • 10
  • 3
    The reason they use it in the `setTimeout` example is because its callback is executed in the global scope, so the value of `this` in the `setTimeout` callback is `window`. In order to keep a reference to the original object, you have to use that method (of storing it in `self`) or some form of using `Function.bind()` – Ian May 30 '13 at 16:29

4 Answers4

9

JavaScript names are lexically scoped, so whenever a name (variable) is encountered in a script, the JavaScript runtime must search up the scopes from where the function was defined.

At the point of definition, this function:

start: function() {
    check();
}

doesn't have access to any check function in its outer scope. Declaring self and binding it to this is a technique used to deal with the (somewhat interesting) intricacies of referring to the current object in JavaScript (because the example code uses window.setInterval).

To reference a function within the current object, it is enough to use this.

var someObject = {
    start: function() {
        this.check();
    },
    check: function() {
        console.log("Check!");
    }
};
Community
  • 1
  • 1
voithos
  • 60,391
  • 10
  • 90
  • 110
2

It's javascript function context, each time you create a function, you create a new context (scope).

In setInterval() function you create a new scope, so this no longer refer as the same this above:

var self = this;
setInterval(function() {
    self.tick();
}, 1000);

You can also manually bind the proper context of your function with bind() (so you don't need self anymore):

setInterval(function() {
    this.tick();
}.bind(this), 1000);

More informations:

julesbou
  • 4,882
  • 4
  • 28
  • 33
1

The point of declaring and initializing a variable like "self" is to deal with the fact that the value of this is determined anew upon each function call. When you've got a function nested inside another function, and that inner function needs access to the value of this from the outer context, then this must be preserved in another variable — "self" in your case. (The name of that variable is unimportant of course.)

In your sample code:

var timer = {
    start: function() {
        var self = this;
        window.setInterval(function(){self.tick();}, 1000);
    },
    tick: function() {
        console.log('tick!');
    }
};

that function passed in to setInterval() needs to use the value of this from the "start" function. When that interval timer function is called, however, this is set to something else (either the global context or null in "strict" mode). Thus, by saving the value of this in the context where that interval timer function is instantiated, its code can use it to access the timer object.

In your second example, declaring and initializing a "self" variable doesn't hurt anything, but it's unnecessary. Sometimes it's handy however, just to clarify the code, though of course a more meaningful name than "self" would be a good idea.

Pointy
  • 371,531
  • 55
  • 528
  • 584
0

of course an object can and should call it's own functions, this is the only way to emulate OOP in javascript. I would say that the practice that the book is using, self = this is bad since this can just be used by itself, however in the first example it is used to preserve the value of this which would otherwise be the this of the function itself not the outer class

aaronman
  • 17,266
  • 6
  • 57
  • 78