Javascript newbie inheritance question

I'm doing a very simple test on inheritance with JavaScript, and it doesn't seem to be working.

I have a Person object type with just one property called 'name', and one method, called sayName().

I want to create a subtype called Woman which inherits the sayName() function from the Person object. When the Woman object is trying to invoke the sayName() method, I am getting an error message, and I don't know why.

Can someone look at my brief code snippet and tell me what I'm doing wrong, please?

function Person(name) {
                this.name = name;
                this.sayName = function() {
                    console.log(this.name);
                };
            }

            function Woman(name) {
                this.name = name;
            }

            Woman.prototype = Object.create(Person.prototype, { // Trying to do Inheritance
               constructor : {
                   enumerable: true,
                   configurable: true,
                   writable: true,
                   value: Woman
               } 
            });

            var woman = new Woman("Jane");

           /* I'm getting an error on the next line: "Uncaught TypeError: undefined is not a function". What I'm doing wrong? */
            woman.sayName();

Open in new window

elepilAsked:
Who is Participating?
 
käµfm³d 👽Connect With a Mentor Commented:
You need to add the sayName method to Person's prototype:

function Person (name) {
    var self = this;
    
    self.name = name;
}

Person.prototype.sayName = function () {
    console.log(this.name);
};

...

Open in new window


Then it should work. You can see examples of such here:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
0
 
elepilAuthor Commented:
kaufmed, thanks for responding. Then can you explain to me why this works? It's almost identical to the my code snippet, simpler actually, and it works without my having to assign sayName() to the prototype:

            function Person(name) {
                this.name = name;
                this.sayName = function() {
                    console.log(this.name);
                };
            }

            function Woman(name) {
                this.name = name;
            }

              Woman.prototype = new Person();
              Woman.constructor = Woman;

            var woman = new Woman("Jane");
            woman.sayName();

Open in new window

0
 
käµfm³d 👽Commented:
Oooooh...  I was afraid you'd ask me that. I'll try my best to explain, but I've just been reading up on this topic myself. I come from a C# background, so this prototypal inheritance is pretty odd to me. Feel free to await further resposnes.

From what I read, it basically comes down to how you set up the inheritance. With my approach, I continued with your use of Object.create. That function creates a new object, and the object that is created has its prototype point to the object that was passed in to the function. In your original code, that means that the prototype of Woman is a new object whose parent prototype is that of Person. Graphically:

null<=Object.prototype<=Person.prototype<=Woman.prototype

When you assign to the prototype, you are basically saying that all instances of a "class" will have that method, and that method will exist only once in memory. When you do not assign to the prototype, each instance of the "class" will have that method, but each instance will have a distinct instance of that method as well. This means you have multiple copies of the method in memory...for no decent reason.

The reason your new code works is because you set Woman's prototype equal to a new instance of the Person "class", and that "class" has its own instance of the sayName method. This may be fine...I'm not 100% sure. But I do know that you've basically got it set up such that any new instance of a Woman points to one instance of Person, because you only created that one and assigned it directly to prototype of Woman. I don't know enough to tell you whether or not this is a good practice.
0
The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

 
elepilAuthor Commented:
kaufmed, correct me if I'm wrong. By making Woman a "subclass" or subtype of Person, if I try to access "sayName" in Woman, it will look at its OWN properties, and it won't find it. It will then look at Woman's prototype and will not find it there. My understanding is that JavaScript would then ascend up the prototypal chain, correct? That means, JavaScript should look next at Person's own properties, and it should find the sayName there. Do we have the same understanding on this?

Because if we do, that was my explanation to myself why the second example works. In fact, I thought it should've worked with BOTH examples, and it has been driving me nuts since this morning why it would not work for the first method.

Is there anything wrong with the way I am understanding this, in your opinion?
0
 
käµfm³d 👽Commented:
...it will look at its OWN properties, and it won't find it. It will then look at Woman's prototype and will not find it there. My understanding is that JavaScript would then ascend up the prototypal chain, correct?
That is what I had read, yes. I *think* the issue with your first is that the method as declared isn't a part of the prototype, though. That is what my example is doing:  adding the method to the prototype.
0
 
elepilAuthor Commented:
To be honest, I was aware that adding the function to the prototype would make it work because my book clearly states that a prototype is shared across ALL instances of that type. In fact, my book explicitly says the above two examples should've behaved identically, except the first example had the added benefit of not having to worry about the Person constructor requiring its parameter. I was so surprised when the first example didn't work.

Anyway, thanks for responding. What I really needed was an explanation why the first method did not work, and how to make it work. The second method is risky because if the Person constructor had code that throws an error if the parameter it's expecting is absent, it will be a problem. For that reason, I'd rather never have to use the second method if I can help it.
0
 
elepilAuthor Commented:
kaufmed, I saw this article: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript. It was using Person as the supertype and Student as the subtype, and it says:

// Create a Student.prototype object that inherits from Person.prototype.
// Note: A common error here is to use "new Person()" to create the
// Student.prototype. That's incorrect for several reasons, not least
// that we don't have anything to give Person for the "firstName"
// argument. The correct place to call Person is above, where we call
// it from Student.

I'm not going to bother seeking an explanation why the second method works, as Mozilla itself flags it as wrong. I'm just going to stick to doing it this way:

        /* Person is the supertype */
        function Person(name) {
            this.name = name;
        }
        /* Define all methods and properties you want to allow subtypes to 
         * access in the prototype. */
        Person.prototype.sayName = function() {
            console.log("I say my name is " + this.name);
        };
        
        /* Man is a subtype of Person */
        function Man(name) {
            /* This is the 'super' counterpart in JavaScript */
            Person.call(this, name);
        }
        /* This is what makes inheritance work. This links Man to Person as a 
         * subtype */
        Man.prototype = Object.create(Person.prototype);
        Man.constructor = Man;
        /* Man object also has a method it wants to allow subtypes to inherit */
        Man.prototype.roar = function() {
            console.log(this.name + " roars!");
        }
        
        /* Boy is a subtype of Man */
        function Boy(name) {
            this.name = name;
            this.pat = function(name) {
                console.log(this.name + " is patting " + name);
            };
        }
        Boy.prototype = Man.prototype;
        Boy.constructor = Boy;
        
        var person1 = new Person("Dad");
        var man = new Man("David");
        var boy = new Boy("PeeWee");
        
        boy.sayName(); // Inherited from Person
        boy.roar(); // Inherited from Man
        boy.pat("Dad"); // boy's own OWN method

Open in new window


Thanks for responding!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.