I am trying to understand the way that javascript passes functions around and am having a bit of a problem groking why a prototype function can NOT access a var defined in a function constructor while a function defined in the constructor can access the var. Here is code that works:
var model = function model() {
this.state = 1;
this.GetState = (function(scope){
return function(){ return scope.state;};
})(this);
}
var othermodel = function othermodel(mdl) {
this.GetStateFn = mdl.GetState;
}
othermodel.prototype.WriteState = function() {
console.log(this.GetStateFn.call());
};
var m = new model();
var o = new othermodel(m)
o.WriteState();
This works and makes sense – the GetState() function can access this.state.
However, if I create GetState as follows:
model.prototype.GetState = (function(scope){
return function(){ return scope.state;};
})(this);
The result will be an error that scope is not defined.
I would prefer to have this work with the prototype method as I do not want a copy of the function in ever model, but it would seem that prototype can’t work because it can’t access the specific instance of the model.
So, can someone provide me with a good explanation of a) what I need to do to get this to work with prototype (assuming I can) and b) if I can’t get it to work with prototype, what is the reason so I can understand better the underpinnings of the issue.
Why not simply write the function this way
The above code will work, as in most cases you will execute code like
m.GetState(). That is an example of invoking a function as an object method. In that case,thisis guaranteed to point to the objectm. You seem to know how the prototype chains work, so I won’t go there.When assigning the function reference to the other model, we use the
.bindto ensure that withinGetState,thispoints tomdl. Reference forbind: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bindYour original IIFE’s were in effect your implementation of bind. The issue was the value of
thiswas wrong. Currently, every time you need to assign models function to some other function, you will need to usebindat all those times. You have tagged your question as node.js,bindis available on theFunctionprototype in node.js and any ES5 compatible browser. If you need to run the above code on older browsers or environments that do not supportbind, replacebindwith your IIFE.As for why your code isn’t working,
Here,
thisdoesn’t refer to the eventual model object (m).thiscan refer to any one of 5 options in javascript. Refer: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/thisLets assume the above code is in an html file inside some script tag. Then
thiswill refer to the window object.windowdoesn’t have any property calledstate, hence theundefined. If you were toconsole.log(this.m, this.o)at the end of you script, you would see the respectivemandoobjects.