Loosing your invocation context (`this`) is one of the JavaScript common pitfalls. Using `this` you can write generic methods that modify the objects they are part of, in an object oriented way. However as you start combining that with more functional programming, passing references to functions into other functions and the like, your function can be invoked in ways you didn't expect, often with no way to access the originally intended `this`.
var a = { total: 0 , inc: function () { this.total += 1 } }; // broken otherThing(a.inc) console.log(a.total) // 0 console.log(total) // NaN function otherThing (incFn) { incFn() incFn() incFn() }
There is a mysterious global called total because functions executed without another context are executed in the global context, and properties on window are global variables.
The increment function is passed in as a reference to the creatively named otherThing, but it no longer has any idea what it's context is. The 'this' isn't tied to how the function is defined, it is tied to how it is called. But of course we can cheat it by binding it permanently ourselves.
One way to bind the function to a set context is the built in 'function.bind(context)'. This returns a new copy of our function, permanently bound to the context provided, irregardless of how we invoke it.
var a = { total: 0 }; a.inc = incTotal.bind(a) otherThing(a.inc) console.log(a.total) // 3 function incTotal () { this.total += 1 } function otherThing (incFn) { incFn() incFn() incFn() }
The other way is to quite simply use any possible reference to the object other than this to define our function.
var a = { total: 0 , inc: incTotal } otherThing(a.inc) console.log(a.total) // 3 function incTotal () { a.total += 1 } function otherThing (incFn) { incFn() incFn() incFn() }
Either of these solutions work fine. The downside to both is the same, you have to have a different copy of the function for each object you want to increment. It's just the nature of the beast, if you want the function to be generic you need to either invoke it with the correct context, or pass all of the parameters in as arguments. Otherwise you need to create different copies of the function to work on each object, which is almost always just fine to do.