2

I append a services property to this:

function Client(){
   this.services = {
      'propertyName' : {}
   };

and then append a method to this, in which I need to reference the services property of the instance of client:

function Client(){
   this.services = {
      'propertyName' : {}
   };
   this.someMethod = function () {
       if (this.services['propertyName']) {
           //do something
       }
   }
}

var clientName = new Client();

But this.services - line 6 is undefined. How can I use a property assigned to this in a method assigned to this? It seems like it should be possible because by the time that method is called by the constructor, the services property will exist for the object. Is this a language limitation? Is it possible? Should it be?

  • @T.J.Crowder What do you mean? It's a function that uses `this` is invoked with `new` - a prototype to create instances of `Client` - how is it not a prototype? –  Sep 26 '15 at 10:41
  • It's not a prototype because it's not a prototype. It's just an object with a property on it. For it to be a *prototype* property, it would have to be on a different object that was the prototype of the object you're trying to use it on. For instance, if you moved `someMethod` *out* of the constructor and did `Client.prototype.someMethod = function() { /* ... */ };`, *that* would be a prototype property (`someMethod`) trying to access a non-prototype property (`services`). (There are also a couple of other ways.) – T.J. Crowder Sep 26 '15 at 10:43
  • @T.J.Crowder Ah, I *think of it* as a prototype for another object, but it's actually called a *constructor* right? –  Sep 26 '15 at 10:46
  • 1
    `Client` is a constructor function, yes. `this` within it (when it's called via `new`) is just referring to an object. (Sometimes called an *instance* of `Client`, but that's really class-based OOP terminology. Doesn't mean it's not helpful sometimes. :-) ) – T.J. Crowder Sep 26 '15 at 10:48
  • Please show us how you call that method. Sounds like a possible duplicate of http://stackoverflow.com/q/20279484/1048572 to me – Bergi Sep 26 '15 at 11:49

1 Answers1

2

But this.services - line 6 is undefined.

That will depend entirely on how you call someMethod. If you call it like this:

clientName.someMethod();

...it'll be fine, because this within the call will be the object created by new Client that you've put the services property on. But in JavaScript, this is not a fixed thing with normal functions, it's set by how you call the function. So:

var f = clientName.someMethod;
f();

...would fail, because this wouldn't be the object you expect. (This isn't true of ES6's new "arrow" functions, which get this from where they're defined, not how they're called.)

You mostly see this when functions are used as callbacks:

doSomething(clientName.someMethod);

...because doSomething doesn't know what object to use as this.

You can fix it by using Function#bind:

doSomething(clientName.someMethod.bind(clientName));

or similarly:

var f = clientName.someMethod.bind(clientName);
f();

Function#bind creates a new function that, when called, will call the original with this set to the argument you give it.


Just to flesh out my ES6 comment above: In ES6, if you had:

function Client(){
   this.services = {
      'propertyName' : {}
   };
   this.someMethod = () => {                  // <== ES6 "arrow" function
       if (this.services['propertyName']) {
           //do something
       }
   }
}

...it wouldn't matter how you called someMethod, this would be what it is where that function was created. V. handy. :-)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 2
    While speaking in ES6, I can assure you, you are *not* [this guy](http://dilbert.com/strip/2010-12-23). Thanks for your help! –  Sep 26 '15 at 10:51