8
\$\begingroup\$

Problem statement

  1. You need to create the Animal base class having four fields:

    a. name

    b. sound

    c. owner

    d. favFood

  2. You need to create a derived class Cat such that every instance of Cat inherits instance members of Animal. In addition, Cat adds a new instance member mode.

  3. Animal and Cat class should enforce encapsulation amidst construction and modification of objects.

Solution

<!DOCTYPE html>
<html>
    <head>
        <title> OOP assignment</title>
        <meta charset="UTF-8">
    </head>
    <body>
    <script language="javascript" type="text/javascript">
        function Animal() { 
            this.name = "No Name"; 
            this.sound = "Grrr";
            this.owner = "Homeless";
            this.favFood = "Anything";
            /* Animal.__proto__ points to Function.prototype */
        }

        /* Animal.prototype.__proto__ points to Object.prototype */ 
        Animal.prototype.setOwner = function(newOwner){
            if (typeof newOwner != 'undefined'){
                    this.owner = newOwner;
                } 
            else
            {
                document.write("Please enter a valid owner name" + "<br>");
            }
        }


        Animal.prototype.getOwner = function(){
            return this.owner;
        }

        Animal.prototype.setName = function(newName){
            if (typeof newName != 'undefined'){
                    this.name = newName;
            } 
            else{
                document.write("Please enter a valid animal name" + "<br>");
            }
        }

        Animal.prototype.getName = function(){
            return this.name;
        }

        Animal.prototype.setNoise = function(newNoise){
            if (typeof newNoise != 'undefined'){
                this.sound = newNoise;
            } 
            else{
                document.write("Please enter a valid animal sound" + "<br>");
            }
        }

        Animal.prototype.getNoise = function(){
            return this.sound;
        }


        /* dog.__proto__ points to Animal.prototype */  
        var dog = new Animal();
        document.write(dog.getName() + "<br />");

        dog.setName("Spot");
        dog.setOwner("Paul");
        dog.setNoise();

        document.write(dog.getName() + "<br />");
        document.write(dog.getOwner() + "<br />");
        document.write(dog.getNoise() + "<br />");



        /* Cat.__proto__ points to Function.prototype */    
        function Cat() {
            /*
                Below line will add members name/sound/owner/favFood to an instance of Cat(),
                with default values
            */
            Animal.call(this); 

            /* another member of Cat instance*/
            this.mode = "Happy";
        }

        /*
            Aftre executing, below line of code,
            Cat.prototype.__proto__ will point to  Animal.prototype;
        */
        Cat.prototype = Object.create(Animal.prototype);

        /*
            In the above line, when Cat.prototype.__proto__ points to Animal.prototype,
            Cat.prototype.constructor automatically points to Animal, so this below line    
        */
        Cat.prototype.constructor = Cat;

        Cat.prototype.getMode = function(){
            return this.mode;
        }

        Cat.prototype.setMode = function(newMode){
            if (typeof newMode != 'undefined'){
                    this.mode = newMode;
            } 
            else{
                document.write("Please enter a valid animal mode" + "<br>");
            }
        }

        /* sophie.__proto__ points to Cat.prototype */
        var sophie = new Cat();

        sophie.setName("Sophie");
        sophie.setOwner("Derek");
        sophie.setNoise("Meow");

        document.write(sophie.getName() + "<br />");
        document.write(sophie.getOwner() + "<br />");
        document.write(sophie.getNoise() + "<br />");
    </script>
    <noscript>
        <h3>This site requires Javascript</h3>
    </noscript>
    </body>
</html>

Output

output

  1. Does the __proto__ hierarchy and contents of Cat.prototype look good?

  2. Do the Animal and Cat class enforce encapsulation amidst construction and modification of objects??

  3. What is the problem, when I say, Cat.prototype = new Animal() instead of Cat.prototype = Object.create(Animal.prototype);?

\$\endgroup\$
5
\$\begingroup\$

Does the __proto__ hierarchy and contents of Cat.prototype looks good?

It looks reasonable. You can test via sophie instanceof Animal or Object.getPrototypeOf(sophie) depending on need.

Did Animal and Cat class enforce encapsulation?

No. We can still do sophie.name='foo' via the objects fields. For instance i could set sophie.name = function() { alert('hello, world'); };

Encapsulation would look more like below whereby we control how and what happens to the values of those fields:

function Animal(name, sound, owner, favFood) {
    var _name = name || "animal";
    var _sound = sound || "roar";
    var _owner = owner || "Homeless";
    var _favFood = favFood || "Jelly beans";

    Object.defineProperties(this, {
        'name': {
            get: function () {
                return _name;
            },
            set: function (name) {
                _name = name;
            }
        },
        'owner': {
            get: function () {
                return _owner;
            },
            set: function (ownerName) {
                _owner = ownerName;
            }
        }
    });
}

There are additional configuration options like leaving off a setter for read-only access, plus writable, configurable and enumerable parameters which can help you completely lock the object down.

What is the problem, when I say, Cat.prototype = new Animal() instead of Cat.prototype = Object.create(Animal.prototype);?

Cat.prototype = new Animal() invokes the function and therefore executes all its statements so it potentially has more/unintended side effects.

\$\endgroup\$
  • \$\begingroup\$ Get and set should be in Animal.prototype \$\endgroup\$ – overexchange Dec 17 '15 at 12:49
  • \$\begingroup\$ It depends upon your requirements. If you do that then you'll need a closure pattern to be able to access var _name etc. Don't make the mistake of just blindly attaching properties and methods to the prototype because "that's how it should be done". It's a horses for courses thing. If you only need a bunch of Animals and your primary concern is privacy and encapsulation then the above is fine. It's easy to read, understand and maintain. If however you're spinning up 1000s of Animals or have other requirements then yes you will benefit from looking at alternatives. \$\endgroup\$ – rism Dec 17 '15 at 20:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.