I have been programming with OOP languages for over 10 years but I'm learning JavaScript now and it's the first time I've encountered prototype-based inheritance. I tend to learn fastest by studying good code. What's a well-written example of a JavaScript application (or library) that properly uses prototypal inheritance? And can you describe (briefly) how/where prototypal inheritance is used, so I know where to start reading?
Nowadays, in modern language, it is being set using __proto__. Example In the given example, there are two objects 'person' and 'GFGuser'. The object 'GFGuser' inherits the methods and properties of the object 'person' and further uses them.
When it comes to inheritance, JavaScript only has one construct: objects. Each object has a private property which holds a link to another object called its prototype. That prototype object has a prototype of its own, and so on until an object is reached with null as its prototype.
That prototype object has its own prototype, and so on until an object whose prototype is null is reached. By definition, null has no prototype, and acts as the final link in this chain of prototypes. This is known as prototypical inheritance and differs from class inheritance.
The most important difference between class- and prototype-based inheritance is that a class defines a type which can be instantiated at runtime, whereas a prototype is itself an object instance.
As mentioned, the movies by Douglas Crockford give a good explanation about the why and it covers the how. But to put it in a couple of lines of JavaScript:
// Declaring our Animal object var Animal = function () { this.name = 'unknown'; this.getName = function () { return this.name; } return this; }; // Declaring our Dog object var Dog = function () { // A private variable here var private = 42; // overriding the name this.name = "Bello"; // Implementing ".bark()" this.bark = function () { return 'MEOW'; } return this; }; // Dog extends animal Dog.prototype = new Animal(); // -- Done declaring -- // Creating an instance of Dog. var dog = new Dog(); // Proving our case console.log( "Is dog an instance of Dog? ", dog instanceof Dog, "\n", "Is dog an instance of Animal? ", dog instanceof Animal, "\n", dog.bark() +"\n", // Should be: "MEOW" dog.getName() +"\n", // Should be: "Bello" dog.private +"\n" // Should be: 'undefined' );
The problem with this approach however, is that it will re-create the object every time you create one. Another approach is to declare your objects on the prototype stack, like so:
// Defining test one, prototypal var testOne = function () {}; testOne.prototype = (function () { var me = {}, privateVariable = 42; me.someMethod = function () { return privateVariable; }; me.publicVariable = "foo bar"; me.anotherMethod = function () { return this.publicVariable; }; return me; }()); // Defining test two, function var testTwo = function() { var me = {}, privateVariable = 42; me.someMethod = function () { return privateVariable; }; me.publicVariable = "foo bar"; me.anotherMethod = function () { return this.publicVariable; }; return me; }; // Proving that both techniques are functionally identical var resultTestOne = new testOne(), resultTestTwo = new testTwo(); console.log( resultTestOne.someMethod(), // Should print 42 resultTestOne.publicVariable // Should print "foo bar" ); console.log( resultTestTwo.someMethod(), // Should print 42 resultTestTwo.publicVariable // Should print "foo bar" ); // Performance benchmark start var stop, start, loopCount = 1000000; // Running testOne start = (new Date()).getTime(); for (var i = loopCount; i>0; i--) { new testOne(); } stop = (new Date()).getTime(); console.log('Test one took: '+ Math.round(((stop/1000) - (start/1000))*1000) +' milliseconds'); // Running testTwo start = (new Date()).getTime(); for (var i = loopCount; i>0; i--) { new testTwo(); } stop = (new Date()).getTime(); console.log('Test two took: '+ Math.round(((stop/1000) - (start/1000))*1000) +' milliseconds');
There is a slight downside when it comes to introspection. Dumping testOne, will result in less useful information. Also the private property "privateVariable" in "testOne" is shared in all instances, als helpfully mentioned in the replies by shesek.
Douglas Crockford has a nice page on JavaScript Prototypal Inheritance:
Five years ago I wrote Classical Inheritance in JavaScript. It showed that JavaScript is a class-free, prototypal language, and that it has sufficient expressive power to simulate a classical system. My programming style has evolved since then, as any good programmer's should. I have learned to fully embrace prototypalism, and have liberated myself from the confines of the classical model.
Dean Edward's Base.js, Mootools's Class or John Resig's Simple Inheritance works are ways to do classical inheritance in JavaScript.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With