2

I want to create a prototype function that has its own scope. For this, I use an anonymous function but I cannot find a way to access the members of the object.

Here is a simplified version of what I am trying to achieve:

function F() {
    this.counter = 0;
} 

F.prototype.increment = (function() {
    var lastIncrementTime = -1;
    var caller = this; // <--- it fails here because this is the Window object
    return function(time) {
        if (time > lastIncrementTime) {
            caller.counter++;
            lastIncrementTime = time;
            return caller.counter;
        }
        return caller.counter;
    }
})();

f = new F();

f.increment();

I know it fails because this does not refer to F or the f object.

Is there a way to access it?

2 Answers 2

6

The immediately invoked function expression (IIFE) itself only gets invoked once, all calls to increment will use the variables as they were last left and not re-var them.

Change the invocation context using call, apply or bind

F.prototype.increment = (function() {
    // this === F.prototype
    // ...
}).call(F.prototype);

The this in this example context will not be instance specific, but be the prototype.


It seems like you actually want to achieve something a little bit different, where you have an independent function to initialise an instance-specific property with it's own closure, when the instance is constructed. These types of actions can consume a bit of memory so don't store too much unique data.

function F() {
    this.counter = 0;
    this.__init_increment(); // create `this.increment`
}
F.prototype.__init_increment = function () {
    var lastIncrementTime = -1;
    this.increment = function (time) {
        if (time > lastIncrementTime) {
            this.counter++;
            lastIncrementTime = time;
        }
        return this.counter;
    };
};
var f = new F();
f.increment(0); // 1
f.increment(0); // 1
f.increment(5); // 2

In this example, this.increment is a different function for each instance, which means you have a different closure for each instance. They are generated by a function in the prototype, which sets the instance property. The generator does not have to be in the prototype, just remember about the invocation context when applying it to your instance.

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

3 Comments

I want to have the instance specific counter. Kolink's version seems to be working just fine, I understand that in your case this will refer to the prototype object, which won't work for an instance specific counter, will it?
@MadEchet If you want something instance specific, you probably want it in the constructor and not in the prototype. Kolink's solution "works" because you're using caller where you could just be using this normally, but that solution still has lastIncrementTime shared across all instances.
That's true, I did not realize that lastIncrementTime was shared. Thanks!
2

Move your var caller = this inside the anonymous function, where this will have been set appropriately.

2 Comments

Or scratch the var called line, and just use this instead of caller within the returned function.
@Paul S. pointed out that a design problem in my code since lastIncrementTime is shared across variables, so I picked his answer.

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.