this
won't refer to the current object when the anonymous function is called because it doesn't follow the obj.func()
pattern which sets this
in the func
scope to obj
and is not bound by some other means. Instead, it refers to the global window object (or undefined
in strict mode).
call
, apply
and bind
don't help since the store
object hasn't been defined yet so there's no object to give as a thisArg
parameter. On the other hand, with store.revert
, this
refers to store
by the time it's called and behaves as expected.
The example seems overly contrived because there's no obvious motivation for setting masterData
as a side effect of the anonymous function that also sets data
. It seems you could just do something like:
// some sameple funcs and data for testing purposes
var getOverviewData = function () { return [42]; };
var shallowCopy = function (a) { return a.slice(); };
var chartData = [24];
var store = {
masterData: getOverviewData(),
revert: function () {
this.data = shallowCopy(this.masterData);
},
data: chartData,
};
console.log(store.data);
store.revert();
console.log(store.data);
In general, if a pattern seems awkward to apply, it's often unnecessary or is a suboptimal way to achieve the desired result. The data
IIFE setter proposed by OP breaks rules of thumb: it doesn't have single responsibility and causes a side effect by mutating an object.
Now, assuming you really do need to access this
from an IIFE while defining this property (or for future readers who do have a legitimate motivation), there are multiple ways to achieve this.
The most obvious and direct solution is to create the store
object and then add the data and mutate it in a second step:
var getOverviewData = function () { return [42]; };
var shallowCopy = function (a) { return a.slice(); };
var chartData = [24];
var store = {
masterData: [],
revert: function () {
this.data = shallowCopy(this.masterData);
},
};
store.data = (function () {
this.masterData = getOverviewData();
return chartData;
}).call(store);
console.log(store.data);
store.revert();
console.log(store.data);
If you don't like this as two steps, you can toss it in an IIFE:
var getOverviewData = function () { return [42]; };
var shallowCopy = function (a) { return a.slice(); };
var chartData = [24];
var store = (function () {
var store = {
masterData: [],
revert: function () {
this.data = shallowCopy(this.masterData);
},
};
store.data = (function () {
this.masterData = getOverviewData();
return chartData;
}).call(store);
return store;
})();
console.log(store.data);
store.revert();
console.log(store.data);
An alternative is using a constructor function as shown here and invoking it with new
which gives you access to the this
context.
The IIFE you're using could be a separate function entirely that accepts an object as a parameter and mutates the two properties on it but this is only mentioned for completeness; it's probably only useful if you plan to reuse the function for multiple objects, in which case you might as well create a full-blown class or non-IIFE constructor function.