0

I have read a few questions like this about it, but I still can't make it work:

Here is my simplified test:

var person = function(name, job)
{
    var self = this;
    self.name = null;

    self.callMe = function()
    {
        alert(self.name + ' please!');
    };

    self.init = function()
    {
        self.name = name;

        setTimeout(function(){self.callMe()}, 1000);
    }();
}

...

person.prototype.callMe = function()
{
    alert('Mister ' + this.name + ' please!');
};


var jonh = new person('john');
var joe = new person('joe');

can test it here: http://codepen.io/anon/pen/bqxmPa?editors=0010

1. Why is the callMe() function in use the original one?

I have read that I must use this to be able to use prototype, which makes sens: since I call a function stored in var self from self.init() the function stored in that var will not be modified by my later prototype... But then how do I do the callback if I don't store the this in self?

2. If I override callMe like person.callMe = function(){}; it will do the same, then why should I use prototype?

I also understand that placing a method in a prototype is good for performance as it is not duplicated in each instance but still shared among them.

Thanks for your teaching!

Community
  • 1
  • 1
antoni
  • 5,001
  • 1
  • 35
  • 44
  • your `self.callMe = function()` clobbers the `person.prototype.callMe = function()` ... so the code runs as expected – Jaromanda X Mar 28 '17 at 02:45
  • `2. If I override callMe like person.callMe = function(){}; it will do the same, then why should I use prototype?` no it wont. That adds a `callMe` function to `person` - which is not the same function as the `callMe` function on an **instance** of `person` – Jaromanda X Mar 28 '17 at 02:46
  • @JaromandaX The original method is called, no 'Mister' in the alert – antoni Mar 28 '17 at 02:48
  • correct, because you clobber the `prototype.callMe` in the constructor where you say `self.callMe =` – Jaromanda X Mar 28 '17 at 02:55
  • not if you have `person.prototype.callMe` defined - oh, wait, `self.callMe` - because of the setTimeout callback – Jaromanda X Mar 28 '17 at 03:16

1 Answers1

1

1.) This is how prototypical inheritence works. When the callback for callMe returns, the code tries to resolve the variable self inside the callback's execution context. Since it is not defined there, it goes up the prototype chain and finds it defined in the execution context on the same level where the callMe and init functions are defined. As callMe is defined on this level, it will simply execute it. If it was not defined on this level, it would execute the function defined on the prototype.

2) If you want to subscribe to OO JS, putting the functions on the prototype will make it clear that they are uhh 'interface methods'. What you are doing here is effectively defining instance methods everytime you 'new' up a class.

Here's how I would implement the Person class as OO

var Person = function(name, job){
  this.name = name;
  this.init();
};

Person.prototype.init = function(){
  setTimeout((function() {
      this.callMe();
    }).apply(this), 1000);
};

Person.prototype.callMe = function(){
  alert('Mister ' + this.name + ' please!');
};

var jonh = new Person('john');
var joe = new Person('joe');
derp
  • 2,300
  • 13
  • 20
  • thanks for your answer, so how to call `person.prototype.callMe()`, if any, from `person.init()`? – antoni Mar 28 '17 at 02:54
  • @JaromandaX no it would not it would say `Uncaught TypeError: this.callMe is not a function` – antoni Mar 28 '17 at 02:58
  • 1
    Resolution of properties on objects has nothing to do with execution contexts (which are important for resolution of variable names). Given `self.name`, the identifier *self* is resolved in the current execution context and, if not found, then up the scope chain (of outer contexts) until found (or not). If found and it's an object, then that object's properties are checked for a *name* property, and if not found, up the `[[Prototype]]` chain until found (or not). – RobG Mar 28 '17 at 03:13
  • Thanks @RobG for clarify that – derp Mar 28 '17 at 03:16
  • @antoni, I accidently deleted that fiddle, here's how you would call the prototype method https://jsfiddle.net/w3knuw82/ – derp Mar 28 '17 at 03:19
  • @derp, thanks for your fiddle, I was expecting a solution to modify my `person.init` and do sth like `person.prototype.callMe.apply(self);` instead, but the concept of overriding a function would be lost if I have to modify the original... – antoni Mar 28 '17 at 03:22
  • Plus another benefit of overriding is to not bother in original class if it is going to be overridden in future. now if I use `person.prototype.callMe.apply(self);` and there is no override in this context it will throw an error :( – antoni Mar 28 '17 at 03:27
  • Do you mean creating a new class of person like extending the person prototype and overwriting the callMe function in that new class? – derp Mar 28 '17 at 03:31
  • Thanks for your implementation, I get the point of your code and it works. Now I will see if someone has a solution to override a function that already exists `self.callMe()` and which is called from a callback `setTimeout(function(){self.callMe()}, 1000);`. – antoni Mar 28 '17 at 03:33