1

Apologies for the title, but there's no succinct way of putting it. I'm working on the following code, which aims to chain a set of counters together, into one big one. To build a clock or whatever.

function subcounter(max, name, trigger) {
    this.index = 0;
    this.trigger = trigger;
    this.name = name;

    this.tick = function() {
        this.index++;
        if (this.index==max) {
            this.index=0;
            this.trigger();
        }
    }

    this.show = function() {
        alert(this.name+' triggered');
    }
}

y = new subcounter(2,'y',function(){alert('finished')});
x = new subcounter(2,'x',y.tick);

for (var index = 0; index < 12; index++) {
    alert ([x.index, y.index]);
    x.tick();
}

This doesn't work as expected. For debugging I replaced the line above with:

x = new subcounter(2,'x',y.show);

And found that 'x triggered' is shown instead of 'y triggered', which I would expect. What's going on here? (Tried in Firefox).


Thanks for your answers or pointing me to documentation on this. However, my brain still fails to understand how a function scoped to one object instance: 'y.show' can ever resolve to that function on a different object instance.

The answer seems to be:

x = new subcounter(2,'x',function() {y.tick();});

But I'd still like to really understand why the original doesn't work as expected.

1

3 Answers 3

2

It should be like

function subcounter(max, name, trigger) {
    var that = this;
    this.index = 0;
    this.trigger = trigger;
    this.name = name;

    this.tick = function() {
        that.index++;
        if (that.index==max) {
            that.index=0;
            that.trigger();
        }
    }

    this.show = function() {
        alert(that.name+' triggered');
    }
}

Otherwise javascript's local scoping will have this contain a reference to the outer context this (i.e., x.this in your case) in the inner functions.

Here is a post detailing the functioning of javascript's local scoping, but it's just the first result I got, it's a pretty common issue.

Sign up to request clarification or add additional context in comments.

4 Comments

I would love to accept this answer. Except it doesn't work. I still get 'x triggered'.
Quite strange: I created a fiddle at jsfiddle.net/H5Bs3 with my modified code (and alerts replaced with console.logs) and it seems to be working.
I see it's correct there. But both Firefox / IE work 'incorrectly'.
I see it logging 'y triggered' in FF as well :(
1

From what I see, it has to do with what the value of 'this' will be inside a function.

Inside a function 'this' will be the value of the object in which the function is called from.

When you call this.trigger(),this is now the object 'x'. So inside the trigger function ie 'show',

this.name will be same as x.name

To get the y objects value, pass the 'y' object itself and call the show function from that object.

function subcounter(max, name, trigger, methodName) {
    this.index = 0;
    this.trigger = trigger;
    this.name = name;

    this.tick = function() {
        this.index++;
        if (this.index==max) {
            this.index=0;
            this.trigger[methodName]();
        }
    }

    this.show = function() {
        console.log(this.name+' triggered');
    }
}

y = new subcounter(2,'y',function(){alert('finished')});
x = new subcounter(2,'x',y, "show");

2 Comments

This works. However it's inflexible. As you can see, I want to be able to pass ANY function to be triggered.
@guillermo-phillips I've updated my answer. Now you can pass the object and method name to call.
0

Javascript changes the scope of this when calling a method from within another object context. Have a look at this article:

http://www.robertsosinski.com/2009/04/28/binding-scope-in-javascript/

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.