Reference to an object's array from within the object in Javascript

127 views Asked by At

I would like to create a new object of the type InvertedPeninsula:

var invertedPeninsula = new InvertedPeninsula();

To create this object type, I use an object constructor function:

var InvertedPeninsula = function() {
  this.inhabitants = [
    {
      name: 'Flanery',
      race: 'Human'
    },
    {
      name: 'Sir Charles',
      race: 'Human'
    },
    {
      name: 'Ealei',
      race: 'Elf'
    },
    {
      name: 'Orado',
      race: 'Spector'
    }
  ];

  this.inhabitants.getRace = function(race) {
    var members = [];
    for (var i=0, l = this.length; i < l; i++) {
      if (this[i].race === race) {
        members.push(this[i]);
      }
    }

    return members;
  };

  this.inhabitants.humans = function() {
    return this.getRace('Human');
  };

  this.inhabitants.elves = function() {
    return this.getRace('Elf');
  };

  this.inhabitants.spectors = function() {
    return this.getRace('Spector');
  };
};

In summary, the constructor creates an object with an array called "inhabitants" which itself contains 4 object literals. The InvertedPeninsula object type constructor then goes on to add four function expressions to the inhabitants array. In other words, the inhabitants array contains 4 objects and 4 methods aswell which one may confirm by printing the contents of the array using a "for-in" iterator.

Everything is behaving like I want, but what I am trying to understand is why on earth this constructor can get away with referencing the inhabitants array without mentioning it's name. In particular:

for (var i=0, l = this.length; i < l; i++) 

Should that code above not be:

for (var i=0, l = this.inhabitants.length; i < l; i++) 

Instead?

Similarly, the human, elves and specter array properties all return:

return this.getRace('Human');
return this.getRace('Elf');
return this.getRace('Specter');

respectively. However, should it not rather be:

return this.inhabitants.getRace('Human');
return this.inhabitants.getRace('Elf');
return this.inhabitants.getRace('Specter');

I made these suggested changes but when trying to call any one of the functions, for example:

invertedPeninsula.inhabitants.humans();

I get these errors:

Uncaught TypeError: Cannot read property 'getRace' of undefined

Uncaught TypeError: Cannot read property 'length' of undefined

I am using Google Chrome 55.0.2883.87 m

Any possible explanations as to what is happening under the hood here?

1

There are 1 answers

0
trincot On BEST ANSWER

It works because the context when you do this:

invertedPeninsula.inhabitants.humans();

... is not invertedPeninsula, but invertedPeninsula.inhabitants and so any reference to this in the method is to invertedPeninsula.inhabitants.

Note also that you define only one property in the constructor: inhabitants.

All the other methods you define in that constructor are not created on this, but on this.inhabitants, and it is that array object that is getting extended with more methods, not the object being constructed.