0

I am tinkering with prototypal inheritance in JavaScript.

I have the code below and I am trying to find out if there is a way of getting the code which makes Cat inherit Animal actually inside the Cat function - so that it is all niceley encapsulated as one unit of code.

The line in question is:

Cat.prototype = new Animal();

Any ideas if this is possible?

    <script>
        function Animal()
        {
            function privateFunction()
            {
                alert("I m private");
            }

            function breathe()
            {
                alert("I am breathing");  
            }

            function eat()
            {
                alert("I am eating");  
            }

            return {
                breathe: breathe,
                eat: eat
            };
        }   

        function Cat(name, age)
        {
            this.name = name;
            this.age = age;
        }

        Cat.prototype = new Animal();

        var joey = new Cat("Joey", 5);

        joey.breathe();
        joey.eat();

    </script>

Edited by DaveAmour

5
Contributors
37
Replies
144
Views
2 Years
Discussion Span
Last Post by Troy III
Featured Replies
  • Troy, I may be wrong, but I think Dave was only trying to wrap all of Cat's code inside the Cat function. And there's a way of doing something similar to it: var Animal = (function() { var _somePrivateFunction = function() { alert("Animal: I'm Private!"); }; var animal = function() … Read More

0

Not unless you are ready to add some extra functionality to the Animal function, for example by adding a .extend() function to Animal itself, so you can do:

Cat = Animal.extend(); 

I wouldn't recommend your style of creating the Animal prototype, including some code style issues. See below for a bit different implementation and style.

       function Animal () {

       };

       Animal.prototype = {

          _privateFunction: function () {
            alert("I'm private");
          },

          breathe: function () {
            alert("I am breathing");
          },

          eat: function () {
            alert("I am eating");       
          }
        };

        Animal.extend = function (constr) {
            var r = function () { }; // empty constructor at first
            r.prototype = Animal.prototype;
            if (constr) r.prototype.constructor = constr;
            return r;
        };

        Cat = Animal.extend(function (name, age) {
          this.name = name;
          this.age = age;
        });

        var joey = new Cat("Joey", 5);
        joey.breathe();
        joey.eat();

Edited by Maurits: Animal.extend could be called without a constructor, and setting it to undefined is not clever.

0

Thanks Maurits - looks interesting, I shall have a tinker.

I have a few different patterns for creating prototypes but why do you think the one above is bad?

0

Also in your example the private function is not private. I can go:

 joey.breathe();
 joey.eat();
 joey._privateFunction();

I got the pattern I am using in my original post off a friend and I think he uses it to hide private functions this way.

0

A friend just showed me this way - any thoughts on that?

        var Cat = function()
        {
            var m = new Animal();

            m.purr = function ()
            {
                alert("Purr purr");
            };

            return m;
        };
0

Sorry for replying a bit late. The issues I have with your original code are:

First:
Not specifically assigning the functions to an actual prototype object obfuscates where they will end up. In your case specifically, you setup an object which doesn't actually assign those functions to the prototype, but to the object "instance", ie the object returned by the constructor. This means that you are creating new functions every time, and at no point in time you are actually using prototypal inheritance, until you are assigning a new Animal object to the prototype of Cat.
You can check this by running the following code:

var t = new Animal();

var s = new Animal();

t.breathe === s.breathe; // returns false!

If you would have been using prototypal inheritance, those functions would have been the exact same function, and the comparison returns true.

Second:
Your private function is actually a closure, and in the way you use it now, it is removed by the GC (garbage collection), as it is not referenced anywhere. Also here is the issue that you are not using prototypal inheritance, but function instances, which means that you cannot actually inherit anything down the line. It is true that closures are the ultimate private functions, but JavaScript does not have private methods. The convention is to indicate methods which are intended to be private by having the name start with an underscore.

Third:
Two small style things: Don't put the opening curly brace on a new line. While in many cases this is not a problem, when you would do something like

function someFunc () 
{
   // do something
   return 
   { 
     key: 'value'
   }
}

the result of this function will be undefined because of automatic semicolon insertion. Second style thing: it helps to put a space between the function name and the parameter list opening parenthesis, as it shows you are defining a function and not calling it.

The suggestion of your friend has the same problem as described above: you are not using prototypes, you are assigning new functions to objects.

Check out the following example:

var T = function () {

};

T.prototype.test = function () {
  alert('test');
};

var a = new T();

var b = new T();

a.test === b.test; // => true

Edited by Maurits: clarification on the private function

0

Hi

Thanks for your comments, all very interesting and useful.

If I question what you have written, it is not intended to be argumentative but rather just the way I learn - if I don't understand something I question it until I do!

Ok so a lot to discuss here so lets do them one at a time so the thread is more manageable.

So lets look at the style in which I declared Animal. My creation of animal was pureley to give me something to be the protoytpe of Cat. This was my area of research so other issues, whilst important, were not really my focus.

I believe the style in which Animal is written is a variation of the Revealing Module pattern which is intended to hide properties and functions in an attempt to mimic classical inheritance a little. I understand what you are saying about making your intentions visble by using an underscore. So it seems there are two schools on this. Are you saying that the Revealing Module pattern is just plain wrong then?

I think the reason that alert(t.breathe === s.breathe); is false is because my Animal function does not return an Animal it all - it returns an anonymous object. I don't think you need to actually use prototype to setup an Animal. You can do it as below and then the functions are equal.

    <script>
        function Animal()
        {
            function privateFunction()
            {
                alert("I m private");
            }

            function breathe()
            {
                alert("I am breathing");
            }

            function eat()
            {
                alert("I am eating");
            }
        }

        var t = new Animal();

        var s = new Animal();

        alert(t.breathe === s.breathe);
    </script>

I think the following test also illustrates this.

    <script>
        function Animal()
        {
            function privateFunction()
            {
                alert("I m private");
            }

            function breathe()
            {
                alert("I am breathing");  
            }

            function eat()
            {
                alert("I am eating");  
            }

            return {
                breathe: breathe,
                eat: eat
            };
        }   

        var Cat = function()
        {
            var m = new Animal();

            m.purr = function ()
            {
                alert("Purr purr");
            };

            return m;
        };

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

        var myCat = new Cat();

        var dave = new Person();

        myCat.purr();
        myCat.breathe();

        alert("Is myCat an instanceof Cat? " + (myCat instanceof Cat));
        alert("Is myCat an instanceof Animal? " + (myCat instanceof Animal));
        alert("Is dave an instanceof Person? " + (dave instanceof Person));
    </script>

Any thoughts?

Edited by DaveAmour

0

I'm gonna jump in on this, seems fun! ^^

I think the reason that alert(t.breathe === s.breathe); is false is because my Animal function does not return an Animal it all - it returns an anonymous object. I don't think you need to actually use prototype to setup an Animal. You can do it as below and then the functions are equal.

    function Animal()
    {
        function privateFunction()
        {
            alert("I m private");
        }
        function breathe()
        {
            alert("I am breathing");
        }
        function eat()
        {
            alert("I am eating");
        }
    }
    var t = new Animal();
    var s = new Animal();
    alert(t.breathe === s.breathe);

Dave, the reason t.breath !== s.breathe it's because every time a new Animal is created it will create a function inside of it named 'breathe'. You see, you 'class' Animal doesn't have any prototyped methods, but when the object is cronstructed it creates those functions only for that object instance. That's why t.breath !== s.breathe.

I guess I use the 'default' layout for prototyping, but there's no real private function, only '_' methods.

var Animal = function() {

};

Animal.prototype.breathe = function() {
      alert('breathing');  
};

var Cat = function(name)
{
    this.name = name;
};
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.purr = function() { 
    alert('puurr'); 
}

var myAnimal = new Animal();
var myCat = new Cat();

myCat.purr();
myCat.breathe();
alert("Is myCat.breathe === myAnimal.breathe ? " + (myCat.breathe === myAnimal.breathe));
alert("Is myCat an instanceof Cat? " + (myCat instanceof Cat));
alert("Is myCat an instanceof Animal? " + (myCat instanceof Animal));

I just tried something to add private methods, but they would not be bound to the 'class', instead the method would be available only insed the block in wich the 'class' was created. Like this:

(function() {

    var _somePrivateFunction = function() {
            alert("I'm Private!");
    };

    Animal = function() {

    };

    Animal.prototype.breathe = function() {
      alert('breathing');  
    };
    Animal.prototype.callPrivateFunction = function() {
        _somePrivateFunction();
    };

    Cat = function(name)
    {
        this.name = name;
    };
    Cat.prototype = Object.create(Animal.prototype);
    Cat.prototype.purr = function() { 
        alert('puurr'); 
    }
}());

var myAnimal = new Animal();
var myCat = new Cat();

myCat.purr();
myCat.breathe();
myCat.callPrivateFunction();
alert("Is myCat.breathe === myAnimal.breathe ? " + (myCat.breathe === myAnimal.breathe));
alert("Is myCat an instanceof Cat? " + (myCat instanceof Cat));
alert("Is myCat an instanceof Animal? " + (myCat instanceof Animal));
alert("Does _somePrivateFunction exists? " + (typeof _somePrivateFunction === 'function'));

This way _somePrivateFunction exists only in the closure which Animal protoype was defined, so it'll only be accessible there.

Edited by AleMonteiro: more info

0

Hi AleMonteiro, JavaScript is always fun!

The code below shows that t.breathe IS equal to s.breathe

You can see it running here:

http://www.paxium.co.uk/content/RevealingModuleTests/Test002.html

Its only when you use the Revealing Module pattern that this is not true.

In any case the functions are always going to be logically equal, the only possible issue is whether in memory we have one of them per object or a shared one. I don't know how JavaScript deals with this under the hood but unless we have a lot of instances of something I don't see this ever being an issue.

    <script>
        function Animal()
        {
            function privateFunction()
            {
                alert("I m private");
            }

            function breathe()
            {
                alert("I am breathing");
            }

            function eat()
            {
                alert("I am eating");
            }
        }

        var t = new Animal();

        var s = new Animal();

        alert(t.breathe === s.breathe);
    </script>

I'm studying JavaScript all day today so hopefully my posts will get better throughout the day!

0

Sorry Dave, my bad, I was so sure of my explanation that I didn't test it =(.
And I guess my explanation is false, because:

var a = function() { alert('X'); };
var b = function() { alert('X'); };

// a === b => false
// a.toString() === b.toString() => true

But you know, one of the things that I love about JS is that it's easy to test it and find out that you're wrong ^^

Anyway, one of the things that I tried to show later in that post is that using Cat.prototype = Object.create(Animal.prototype); makes instanceof work properly.

Edited by AleMonteiro

0

That's ok JavaScript is the most confusing language ever.

I used to think I must be stupid as I couldn't understand JavaScript but now realise it doesn't even understand itself!

instanceof does work fine again unless you are using the revealing module pattern.

I'm quite happy with prototyping - that is I'm not against it but I just don't like how you cannot do it all inside the one function. That kind of annoys me and drives my OCD crazy!

If you have some spare time and want proof that JavaScript is crazy check this video out, it's very funny too.

https://www.youtube.com/watch?v=PV_cFx29Xz0

0

Yep its a great video.

I have learned a lot today but still a way to go I think!

0

In my Animal, Cat example, if Animal were to be a kind of abstract class and I would only ever be creating Cats, Dogs etc then I suppose it doesn't matter that I didn't create my Animal functions via it's prototype - as long as I set my Cat and Dog to have an Animal as it's prototype then there won't be any issues of functions repeating again and again in memory. I think that sounds right, does everyone agree with that?

0

@Maurits - just looked at your curly braces on new line issue.

I do know to not put these on new lines for my return statements eg:

            return {
                breathe: breathe,
                eat: eat
            };

I will always put them on a new line for function declarations though as I have always done that in all curly braced langauges I have used (C, C++, Pascal, Java, C#, JavaScript etc) and it is a preferred style of mine. I find it easy to line the two up with my eye to see where things start and end which is particularly useful with many nested levels.

Also sorry I also don't like the space between function and () idea either. If you can't see whether a function is being defined or called then you are in a whole lot of trouble. Also it would drive my OCD crazy. I know this is just a style issue but I don't like it but each to their own I think.

0

Oh, I just started whatching and I'm loving it!

Oh boy. I had to turn him off. That guy must be the most annoying bloke in his town. I felt like punching him through my screen. :(

I never understood OOP / JS. Why is it so complicated? To do something you can do in a few lines in other languages, you have to go out of your way to create some ridiculous construct - which very few people seem to know about.

0

I often find some guys either annoying or funny, it's a fine line sometimes.

Why is it so complicated? Good question! Let me know if you figure it out!

0

I often find some guys either annoying or funny, it's a fine line sometimes.

Yes very subjective I know.

I have no idea, and not likely to have either.

http://stackoverflow.com/a/21220964 - I think Ale was refering to this post. Seems to be the most likely candidate to me too. What a palaver. I'm so pleased I only have to dip into JS every now and again. If I had to work in JS day in day out I think I'd scream.

0

Thanks diafol that's an interesting post.

The thing that really bugs me though is that whatever technique you use involving prototypes to simulate classes and facilitate code reuse, you have to do it in many lines of disjointed code. You cannot do it in one function. This just stinks in terms of SRP and makes code a monolithic mess of spaghetti which is difficult to understand and difficult to maintain.

Hence the reason for this post and my original question in the first place.

I think the reality is we just have to accept that JavaScript is a pile of crap but we are stuck with it so we may as well at least try and understand how it works, even if we don't like what we find!

0

I always thought that JavaScript is the only language that has the potential of producing a live, living & evolving A.I.

0

DaveAmour says:
(is there) "a way of getting the code which makes Cat inherit Animal actually inside the Cat function".

But that - my friend - (in case I understand your sentence well) is a request of a self defeating puropse.

Wouldn't it, than, require a Dog to define the Animal inside a Dog all over again?[!]

Could you please clarify, or better emphasize on: what are you after, or what would be the aim of it?

Regards.

2

Troy, I may be wrong, but I think Dave was only trying to wrap all of Cat's code inside the Cat function.

And there's a way of doing something similar to it:

var Animal = (function() {
    var _somePrivateFunction = function() {
        alert("Animal: I'm Private!");
    };
    var animal = function() {
    };
    animal.prototype.breathe = function() {
        alert('Animal: Breathing');  
    };
    animal.prototype.callPrivateFunction = function() {
        _somePrivateFunction();
    };
    return animal;
}());

var Cat = (function() {
    var cat = function(name) {
        this.name = name;
    };
    cat.prototype = Object.create(Animal.prototype);
    cat.prototype.purr = function() { 
        alert('Cat ' + this.name + ' : puurr'); 
    }
    return cat;
}());

var myAnimal = new Animal();
var myCat = new Cat("Olinda");
myCat.purr();
myCat.breathe();
myCat.callPrivateFunction();

var tests = [
    ("Is myCat.breathe === myAnimal.breathe ? " + (myCat.breathe === myAnimal.breathe)),    
("Is myCat an instanceof Cat? " + (myCat instanceof Cat)),
("Is myCat an instanceof Animal? " + (myCat instanceof Animal)),
("Does _somePrivateFunction exists? " + (typeof _somePrivateFunction === 'function'))
    ];

alert(tests.join("\r\n"));

Edited by AleMonteiro

Votes + Comments
despite some gnarly comments later on in the thread, I like this!
0

AleMonteiro says:
"Troy, I may be wrong, but I think Dave was only trying to wrap all of Cat's code inside the Cat function."

But than, why would he need "Animal"?

0

But than, why would he need "Animal"?

It's just about the code specific for Cat inside Cat function. And all the code for Animal inside the Animal function.

The point is to use inheritance inside the function itself, sou you don't need to set Cat.prototype after the Cat function declaration.

-1

as already stated - it's a self defeating aim and purpose.

People need to learn to respect LiveScript for what it is;
in order be able to learn how it is.

And in general, probably stop demanding rigid behavior expected from old static procedural languages.

Animal is a >>generic<< object
"Cats" and "Dogs" are >>specific<< objects.

Therefore, (for our own benefit) we can, and we should use Generic Objects to easily create specific [animals] - not the other way around, nor completely misunderstand the point of inheritance.

0

As I understand it, the purpose of the closure when defining the object is just about code organization and keeping some desired functions hidden from the global context.
The objects will still be generic and dynamic even if defined inside a closure to(just to wrap it all).

People need to learn to respect LiveScript for what it is;
in order be able to learn how it is.

And in general, probably stop demanding rigid behavior expected from old static procedural languages.

I ain't arguing any of that! Rigid behavior is the last I want! I have so much fun with JS because it's so dynamic and there's so many ways of acomplishing the same functionality.
As I said in another post, being able to modify any object or method, from the browser, APIs or whatever, it's just too much intriguing!

document.getElementById = function() { alert("I don't care! =P"); };

Edited by AleMonteiro

0

gnarly... just learned a new word!
And you're right about it, my concept of JavaScript is not entirely rational.
But just let me try to make my point: I've been doing a lot of frontend with JS for the last 8 years, and the only thing that keeped me from going, totally, crazy is trying new things and having fun with it.

Forgot to mention early, as said in the video posted by Dave, there's some libs for class creation in JS.
http://dkraczkowski.github.io/js.class/
http://classify.petebrowne.com/#/api
http://joose.it/

I tried js.class a couple of years ago, it works well, but it just doesn't feel right to me. One problem that I remember is that Visual Studio intellisense didn't seem to work.

Edited by AleMonteiro

0

Hi guys

I haven't forgot about this thread. I am busy the next 2 days but will have a good play around with your ideas on Sunday.

Thanks to everyone who has understood my original question and posted useful and constructive comments, much appreciated.

0

Just managed to have a quick play around. Off to work in a mo though.

I realise that one of my problems is that when I am tinkering with code and trying out different ides I like to inspect my objects to see what has actually happened. For this I use a combination of Visual Studio and browser consoles/developer tools.

These all seem to give different results thouhg - look at the screen dumps I collected all looking at the same web page and object. How do you guys cope with this? What do you use for the truth about an object?

Browsers.png

Edited by DaveAmour

0

I don't really bother analysing the built-in functions of browsers or IDEs.
The basic commands are all(happily) the same, but each browser may have it's own built-in functions. The same occurs with CSS properties.
I usually have a fix.js to handle commum missing methods on base objects and I really just want to know if the object has what it's supposed to.

And from time to time we can't scape debbuging JS trough developer consoles, but I think it's a slow method.

I've been using just a log function to expose the object as JSON in the console:

var _log = function(label, obj) {
    if ( typeof console.log === 'function' ) {
        console.log(label + ": " + JSON.stringify(obj, undefined, '\t'));
    }
};

The JSON lib: http://www.json.org/js.html

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.