Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

An example of prototypical inheritance that does not involve simulating classical inheritance?

I've read the following QAs and all of them examine using prototypical inheritance to simulate classical inheritance.

Good Example of JavaScript's Prototype-Based Inheritance

javascript inheritance

Using inheritance patterns in JavaScript

Is there not one working example of prototypical inheritance in the wild? Simulating life-forms, maybe? What problems, other than those created or not adequately solved by the programming language, would benefit from raw prototypical inheritance?

like image 640
Samuel Danielson Avatar asked Apr 01 '11 14:04

Samuel Danielson


People also ask

How prototypical inheritance is different from classical inheritance?

Classical inheritance is limited to classes inheriting from other classes. However prototypal inheritance includes not only prototypes inheriting from other prototypes but also objects inheriting from prototypes.

What is prototypical inheritance?

Simply put, prototypical inheritance refers to the ability to access object properties from another object. We use a JavaScript prototype to add new properties and methods to an existing object constructor. We can then essentially tell our JS code to inherit properties from a prototype.

Does JavaScript have classical inheritance?

Inheritance is an important concept in object oriented programming. In the classical inheritance, methods from base class get copied into derived class. In JavaScript, inheritance is supported by using prototype object.

Is prototypal inheritance OOP?

Both classical and prototypal inheritance are object-oriented programming paradigms. Objects in object-oriented programming are abstractions that encapsulate the properties of an entity.


1 Answers

Inheritance is inheritance, so you can get the same basic functionality out of either.

One benefit of prototypal inheritance in JavaScript is to allow dynamic run-time addition of new methods or alteration of old ones available to all objects (without adding a per-object memory penalty).

This can be dangerous, especially when the built-in methods such as String or Object, have their built-in methods over-ridden in a backward-breaking (or forward-threatening) manner.

String.prototype.replace = function () {
    return 'hahaha';
};

But it can be powerful when some browsers' or libraries' implementations are inadequate in functionality or lagging in performance.

It also helps modularity, extensibility, and improvement of libraries. If you include someone's library and find that their implementation for a particular method could be better optimized, you can drop in their code without tampering with it, while still having the ability to improve it or add features to it and benefiting all objects defined outside their library (at least as soon as you start adding it to the prototype). A library could even swap implementations based on user preference (probably not usually a good idea though if it may interfere with other code using that method) or let them dynamically define the names of the methods they want to use.

And the prototypal behavior even comes into play even within a "class" since you can take advantage of the convenience of storing directly on the object (though it does add to memory in such cases and probably better just to create a new class--but it still can be convenient).

function Dog (type) {
    if (type === 'poodle') {
        this.bark = function () {
            alert('(yapyapyap)');
        };
    }
}
Dog.prototype.bark = function () {
    alert('(woof)');
};

var muffy = new Dog('poodle');
muffy.bark(); // '(yapyapyap)'
var rover = new Dog();
rover.bark(); // '(woof)'

The fact that the prototype is something which can be dynamically changed or swapped in the prototypal approach of JavaScript also lets you dynamically create new classes at run-time unlike some more traditional languages, at the very least offering some more succinct expressivity:

function Creature () {}
Creature.prototype.respire = function () { return 'oooooh'; };

function createClass (o, f) {
    f = f || function f () {}
    f.prototype = (typeof o === 'function') ? o.prototype : o.constructor.prototype;
    f.prototype.constructor = f;
    return f;
}

var animals = ['Dog', 'Tiger', 'Lion', 'Frog', 'Kangaroo'];
animals.forEach(function (animal) {
    window[animal] = createClass(Creature);
});
var rover = new Dog();

Finally, you can avoid strict is-a hierarchies, by borrowing just what you need, while still taking advantage of the inheritable features:

function createMixinClass (old, constructor, newMethods) {
    if (typeof constructor === 'object') {
        newMethods = constructor;
        constructor = null;
    }
    var proto = old.prototype, constructor = constructor || function () {};

    for (var m in proto) {
        constructor.prototype[m] = proto[m];
    }
    for (var method in newMethods) {
        if (!newMethods[method]) {
            delete constructor.prototype[method];
        }
        else {
            constructor.prototype[method] = newMethods[method];
        }
    }
    return constructor;
}

var Cat = createMixinClass(Dog, {bark:null, meow: function () {alert('meow');}});
var kitty = new Cat();

In short, I don't think there's anything so different that lets you handle new kinds of problems, but it offers more flexibility, especially with some reusable utilities made handy.

like image 132
Brett Zamir Avatar answered Nov 14 '22 23:11

Brett Zamir