2

I am trying to understand the prototype inheritance in Javascript. There have been several questions already asked on this, but they do not seem to address the confusion I am having.

How does JavaScript .prototype work?

What is the 'new' keyword in JavaScript?

There are also some great resources on the internet.

http://www.webdeveasy.com/javascript-prototype/

http://javascriptissexy.com/javascript-objects-in-detail/

When I read those resources, I think I understand prototypical inheritance, but when I try some tests in the browser console I realise I am missing something.

Based on the code example below:
(1) why is the added prototype function description() not visible on the parent object animal ?
(2) why is an object created after the description() function is added now missing the original object attributes: name and color?

Example:

Create a simple object.

function animal(){
    var name;
    var colour;
 }

Create two new objects based on the prototype animal

> cat = new animal();
< animal {}
> cat.name = 'cat';
> cat.color = 'black';

> cat
< animal {name: "cat", color: "black"}

Add an attribute to one object only

> dog = new animal();
> dog.name = 'dog';
> dog.color = 'brown';
> dog.bite = 'hurts';

> dog
< animal {name: "dog", color: "brown", bite: "hurts"}


> animal.prototype.description = function(){
  console.log('A ' + this.name + ' is ' + this.color); }
< function (){
  console.log('A ' + this.name + ' is ' + this.color); }

Add a new function as a prototype. This all works as I expected it to.

> animal
< function animal(){
   var name;
   var colour;
}


> dog
< animal {name: "dog", color: "brown", bite: "hurts", description: function}
> cat
< animal {name: "cat", color: "black", description: function}

Here is the confusion. the new function description appears on both of the existing dog and cat objects, but it does not appear on the parent object animal

> cat.description;
< function (){
  console.log('A ' + this.name + ' is ' + this.color); }

> cat.description();
< A cat is black 

A new object cow created from the parent animal now has only the description function, but not the name or color

> cow = new animal();
< animal {description: function}

> cow
< animal {description: function}

EDIT

Based on @Quince's answer, I went back to the browser, but am still confused:

>animal = function(){
   this.name;
}
<function (){
   this.name;
}
>animal
<function (){
   this.name;
}
>cat = new animal();
<animal {}
>cat
<animal {}

In this case the new object cat doesn't seem to inherit the name property from the parent.

Community
  • 1
  • 1
port5432
  • 5,889
  • 10
  • 60
  • 97
  • 1
    ah if you were to set them to undefined or an initial value you would see them `function Animal(name, colour){ this.name = name; this.colour = colour; }` – Quince Oct 21 '14 at 13:11

1 Answers1

4

in this example here

function animal(){
    var name;
    var colour;
 }

name and colour are private to animal and as such can not be accessed.

now when you run this

 cat = new animal();
< animal {}
> cat.name = 'cat';
> cat.color = 'black';

you are actually not setting those private name and colour attributes inside animal you are giving it new attributes called name and colour

when you run the following

animal.prototype.description = function(){
  console.log('A ' + this.name + ' is ' + this.color); 
}

animal is being given a publicly accessible function called description which is why you can see it when you create a cow, but actually this function will not print anything yet as the animal class does not have a name or color attribute.

options you have here are to change animal to

function animal(){
    this.name;
    this.colour;
 }

although this gives no advantages other letting you know you can set this attributes of the animal, you will still need to set them in order for description to print anything.

Another option if wanting to keep things private and public is to use something along the lines of the revealing module pattern which allows js to keep attributes private to an object by declaring them outside of the object you return.

function Animal() {
    //private artibutes
    var name;
    var colour;
    //return publically avaliable functions/attibutes
    return {
        description: function () {
            console.log('A ' + name + ' is ' + colour);
        },

        setName: function (nameIn) {
            name = nameIn;
        },

        setColour: function (colourIn) {
            colour = colourIn;
        },
        getName: function () {
            return name;
        },

        getColour: function () {
            return colour
        }
    }
};

now the only way to access the private name and color is to use the publicly available functions returned here is a fiddle showing it in action http://jsfiddle.net/leighking2/fxrLpj9v/

Oh and just realized i never actually answered the question in the title, so when you print animal you do not see the added description function as this function is attached to the prototype, animal when printed raw is just a constructor. Anything created using new Animal will inherit from animal's prototype which is why it can be seen in dog and cow

Quince
  • 14,790
  • 6
  • 60
  • 69
  • I see. So if the attributes are to be inherited, should they be defined as **this.name;** for example? – port5432 Oct 21 '14 at 12:36
  • 1
    yes, sorry was just updating the answer with that, will give another example as well – Quince Oct 21 '14 at 12:38
  • Thank you ... I am grappling with that. I also asked a refinement here: http://stackoverflow.com/questions/26487480/javascript-prototype-attribute-not-visible-on-parent – port5432 Oct 21 '14 at 13:09
  • 1
    ok realized i didn't answer the actually question so made one final update at the bottom to discuss why you could not see the added function on animal – Quince Oct 21 '14 at 13:23