20. Penguins, Properties, and the Prototype


#1

https://www.codecademy.com/en/courses/objects-ii/3/5?curriculum_id=506324b3a7dffd00020bf661

Why is this code correct, but the one below it is not? Notice that the difference is where Emperor.prototype = new Penguin(); is placed.

CORRECT:

function Penguin(name) {
    this.name = name;
    this.numLegs = 2;
}

// create your Emperor class here and make it inherit from Penguin
function Emperor(name) {
    this.name = name;
}
// create an "emperor" object and print the number of legs it has
Emperor.prototype = new Penguin();

var emperor = new Emperor("Bubbles");

console.log(emperor.numLegs);

INCORRECT:

function Penguin(name) {
    this.name = name;
    this.numLegs = 2;
}

// create your Emperor class here and make it inherit from Penguin
function Emperor(name) {
    this.name = name;
    Emperor.prototype = new Penguin();
}
// create an "emperor" object and print the number of legs it has

var emperor = new Emperor("Bubbles");

console.log(emperor.numLegs);

It says to create your Emperor class and make it inherit from Penguin. Wouldn't I put the code that makes Emperor a prototype of Penguin in the actual Emperor constructor, and not on the outside?


#2

@drbartsch,
From
http://javascript.crockford.com/survey.html
[quoting]

Constructor

Functions which are used to initialize objects are called constructors.
The calling sequence for a constructor is slightly different than for ordinary functions.
A constructor is called with the new prefix:

new Constructor(parameters...)

By convention, the name of a constructor is written with an initial capital.

The new prefix changes the meaning of the this variable.
Instead of its usual value, this will be the new object.

The body of the constructor function will usually initialize the object's members.
The constructor will return the new object, unless explicitly overridden with the return statement.

The constructed object will contain a secret prototype link field,
which contains a reference to the constructor's prototype member.

Prototype

Objects contain a hidden link property.
This link points to the prototype member of the constructor of the object.

When items are accessed from an object by the dot notation or the subscript notation,
if the item is not found in the object
then
the link object is examined.
If it is not found in the link object,
and if the link object itself has a link object, then that link object is examined.

If the chain of link objects is exhausted, then undefined is returned.
( this occurs in your 2nd code-bit, as =numLegs= cannot be found )

This use of prototype link chains provides a sort of inheritance.

Members can be added to the prototype by assignment.
Penguin.prototype.sayName = function() { console.log( "I am " + this.name); };

Here we define a new class Demo, which inherits from class Ancestor, and adds its own method foo.

function Demo() {}
Demo.prototype = new Ancestor();
Demo.prototype.foo = function () {};

[end-quoting]


Visualizing the 1st code-bit

function Penguin(name) {
    this.name = name;
    this.numLegs = 2;
}

// create your Emperor class here and make it inherit from Penguin
function Emperor(name) {
    this.name = name;
}
// create an "emperor" object and print the number of legs it has
Emperor.prototype = new Penguin();

var emperor = new Emperor("Bubbles");

console.log(emperor.numLegs);

will look like

J a v a S c r i p t and it's == p r o t o t y p e - C h a i n ==

They want you to set up the chain:

        OBJECT
  Object.prototype
           ^
           |
  Penguin.prototype  (( is empty ))
           |                              ^
           |                              | 
           |                    Penguin Class-Constructor
           ^                   | with this constructor
           |                   |  you can create Instance's of Penguin
           |
           |    <<== You define this link in the Chain using
           ^            Emperor.prototype = new Penguin();
           |
  Emperor.prototype ((is empty))
           |               ^
           |               | 
           |          Emperor Class-constructor
           ^                   | with this constructor
           |                   |  you can create Instance's of Emperor
   /Instance /      <---   using new Emperor("aName");
   | of      |
   | Emperor |
    The Emperor-Instance has access
     to Penguin.prototype
     via the Emperor-prototype which is
      -chained- to the Penguin-prototype

#3

@leonhard.wettengmx.n, what happens when I set prototype like Emperor.prototype = new Penguin;?

I know in other instances using Penguin instead of Penguin(); is completely different because I made that mistake in previous exercises many times, but in this case the subsequent emperor.numLegs still seems to work as expected.

I think Penguin is a reference to Penguin()* (I just realised the reference I used to figure out my past errors is a JQuery site but the results seemed to conform to that idea)...

Then is Emperor.prototype = new Penguin; saying that Emperor's prototype should be like variable Penguin's and since the value of var Penguin is constructor/class Penguin(); that constructor/class value gets passed to Emperor.prototype and it all still works out in the end (with one extra layer of obfuscation) or???


*Edit: Paragraph 3-- mistakenly filled my Penguin() parameter with text :joy::sob:


#4

@msfrisby,
First of all the clearify the usage of the pair-of-parenthesis-( ) or not.....

If you define a function you use the parenthesis as so-called parameter holders.
like

function justAFunction( param1 ) { console.log( param1 ); }

if you now use

justAFunction();

the Javascript interpreter will interprete the parentheses-() as an execution indicator.
the Javascript Interpreter will allow you
to pass on so-called arguments in this execution-indicator
like

justAFunction("Hello")

===============================================

Concerning the prototype story
place the following code in labs.codecademy.com <javascript>
and try to comprehend what is going on...

function Penguin(name) {
    this.name = name;
    this.numLegs = 2;
}

// create your Emperor class here and make it inherit from Penguin
function Emperor(name) {
    this.name = name;
}
// create an "emperor" object and print the number of legs it has

console.log("Create Emperor Instance before expanding prototype chain");
var emperor1 = new Emperor("Bubbles1111");
console.log("The value in the secret =constructor= field is:");
console.log(emperor1.constructor.toString());
console.log("How many Legs before : " +emperor1.numLegs +"\n\n");

//Expanding the prototype-chain
//and make it inherit from Penguin
Emperor.prototype = new Penguin();

console.log("Create Emperor Instance after expanding prototype chain");
var emperor2 = new Emperor("Bubbles2222");
console.log("The value in the secret =constructor= field is:");
console.log(emperor2.constructor.toString());
console.log("How many Legs emperor2 after : " +emperor2.numLegs+"\n");
console.log("How many Legs emperor1 before : " +emperor1.numLegs +"\n\n");

console.log("a FOR in loop over emperor1 ");
for (var x in emperor1) {
    console.log(x);
}
console.log("a FOR-IN loop over emperor2 ");
for (var x in emperor2) {
    console.log(x);
}
console.log("\n\nFOR-IN with check on hasOwnProperty()");
for (var x in emperor2) {
    console.log("Property-key ["+x +
                "] is property-key of emperor2 "+
                emperor2.hasOwnProperty(x));
}

#5

Hi @leonhard.wettengmx.n,

Thank you so much for your help. I ran the program in labs and think I understand everything except:

Property-key [numLegs] is property-key of emperor2 false

  • Since emperor2 inherited properties from Penguin I expected this to be true; why is it false?*

  • I did notice that, even though the Emperor class prototype was changed, the first instance, emperor1, didn't have numLegs.
    Is this because he was created before the prototype extension?


I also tried changing the program so that Emperor.prototype = new Penguin; [sic] comes before the declaration of emperor1 and now both emperor1 and emperor2 have numLegs: 2. (Labs did warn that I "forgot" the parentheses.)

the Javascript interpreter will interprete the parentheses-() as an execution indicator.

  • Does this mean the above declaration worked because for the purpose of prototype extension the constructor does not need to execute?

Thank you again.


Apr 19 edit:

*After studying more I think I read that inherited properties =/= "own" properties, which would explain why emperor2.hasOwnProperty returned false?


#6

Sorry, I have a question please. In mathematical terms, if x~y and y~z , then x~z.(Transitive Property).

My question goes thus: why cant we set var emperor = new Penguin("xxxxx"); from the first place? Thank you in Advance.