Reputation: 12410
I have read this answer and IIFE but I can't seem to find the correct solution to my problem.
I have a simple class here:
define(['jquery'], function($) {
// Need 'self' because someCallback() is being called with .call() and 'this' changes
var self;
function Foo(number) {
self = this;
this.someNumber = number;
}
Foo.prototype = {
someCallback: function () {
//Use self because 'this' changes to a DOM element
var num = self.someNumber;
//Do something with the num
return num * 2;
}
};
return Foo;
});
and someCallBack()
is being called by a jQuery plugin using .call()
. Because of this, the context changed, hence the use of the self
variable.
However, this is wrong because:
define(['foo'], function(Foo) {
describe('context question', function () {
var foo1 = new Foo(1);
var foo2 = new Foo(2);
it('"this" should work', function () {
var call1 = foo1.someCallback.call(this); // 4
var call2 = foo2.someCallback.call(this); // 4
expect(call2).toBe(4); // Only works because it is 'new' last
expect(call1).toBe(2); // Fails because 'self' is taken from foo2
});
});
});
How exactly should I wrap the self
variable to make this code work?
Upvotes: 1
Views: 59
Reputation: 19356
Two ways of calling an object method which stores its own this value include
Define the method as a nested function which references its this value in a closure which stores this
value in a variable. The function defined could be anonymous or declared with a name but must be evaluated each time a class instance is created, so as to create a new Function object capturing different values of self
in function scope.
Take a statically defined function object and bind its this value using bind
. Bind creates a new wrapper function object each time it is called.
The first method looks like (without Jquery or Jasmine):
function Foo(number)
{ var self = this;
this.num = number;
this.someCallback = function() // method with new Foo object stored as self in function scope
{ // something with num:
return self.num * 2;
}
}
and the second method could look like
function Foo(number)
{ this.num = number
this.someCallback = this.someCallback.bind(this); // bind prototypical method as local method.
}
Foo.prototype = {
someCallback: function () {
// this value is bound by constructor;
//Do something with the num
return this.num * 2;
}
};
Upvotes: 1
Reputation: 19792
You could probably just use the revealing module pattern and declare it as a "global" variable (local to the module):
define(['jquery'], function($) {
var someNumber;
function Foo(number) {
someNumber = number;
}
Foo.prototype = {
someCallback: function () {
return someNumber * 2;
}
};
return Foo;
});
Upvotes: 1