1

I'm trying to create a prototype of a prototype in Javascript. Instead of the following functionality, utilizing normal prototypes, built from scratch, I'd like my prototypes to inherit certain methods without me adding them to each one.

So instead of this code, where I've added a method logDependencies() within the prototype to check if there are any instances of Dependency within the Car instance:

function Dependency(data) {
    this.data = data;
}

function Car(color) {
    this.color = new Dependency(color);

    this.logDependencies = function () {
        for (var key in this)
            if (this.hasOwnProperty(key))
                if (this[key] instanceof Dependency)
                    console.log("Dependency: " + key);
    };
}

var lamborghini = new Car("red");

lamborghini.logDependencies();

I'd like to instead have all of my prototypes inherit the function logDependencies(), without me manually adding it.

How can I do this?


Update:

For those of you confused by my wording:

I'm trying to make a prototyping function that allows me to create prototypes who inherit certain properties and methods, passing them down the inheritance chain.

A related article by Douglas Crockford (emphasis my own):

My journey was circuitous because JavaScript itself is conflicted about its prototypal nature. In a prototypal system, objects inherit from objects. JavaScript, however, lacks an operator that performs that operation. Instead it has a new operator, such that new f() produces a new object that inherits from f.prototype.

This indirection was intended to make the language seem more familiar to classically trained programmers, but failed to do that, as we can see from the very low opinion Java programmers have of JavaScript. JavaScript's constructor pattern did not appeal to the classical crowd. It also obscured JavaScript's true prototypal nature. As a result, there are very few programmers who know how to use the language effectively.

Fortunately, it is easy to create an operator that implements true prototypal inheritance. It is a standard feature in my toolkit, and I highly recommend it for yours.

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

The object function untangles JavaScript's constructor pattern, achieving true prototypal inheritance. It takes an old object as a parameter and returns an empty new object that inherits from the old one. If we attempt to obtain a member from the new object, and it lacks that key, then the old object will supply the member. Objects inherit from objects. What could be more object oriented than that?

So instead of creating classes, you make prototype objects, and then use the object function to make new instances. Objects are mutable in JavaScript, so we can augment the new instances, giving them new fields and methods. These can then act as prototypes for even newer objects. We don't need classes to make lots of similar objects.

For convenience, we can create functions which will call the object function for us, and provide other customizations such as augmenting the new objects with privileged functions. I sometimes call these maker functions. If we have a maker function that calls another maker function instead of calling the object function, then we have a parasitic inheritance pattern.

I have found that by using these tools, coupled with JavaScript's lambdas and object quasi-literals, I can write well-structured programs that are large, complex, and efficient. The classical object model is by far the most popular today, but I think that the prototypal object model is more capable and offers more expressive power.

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • If `dependency` is being used as a constructor, then why does it have a return statement? – Wio Jul 08 '14 at 01:35
  • Are you saying you want logDependencies to be available globally or are you saying that you want logDependencies to be called without you having to manually call it? – joshboley Jul 08 '14 at 01:37
  • My point is that the return statement is meaningful if you call it as `dependency('red')`, but if you call it as `new dependency('red')` then the return statement is meaningless because the result of `new` will always return `this`. – Wio Jul 08 '14 at 01:39
  • @joshboley I'm saying I want to create a prototype that inherits the method `logDependencies()` from it's own prototype. A special prototype that inherits certain methods. No, I don't want the methods to be global. –  Jul 08 '14 at 01:40
  • Okay @jt0dd, can you give an example of code you would expect to work smoothly were you to implement what you are asking for? – Wio Jul 08 '14 at 01:44
  • @Wio it's done. And note, I think that may be the wrong way to go about it, but hopefully it explains what I'm asking. –  Jul 08 '14 at 01:53
  • You state that you've "*added a method […] within the prototype*", but your code is not even using any prototype??? – Bergi Jul 08 '14 at 01:53
  • @Bergi car() is a prototype! [JS Prototypes](http://www.w3schools.com/js/js_object_prototypes.asp) –  Jul 08 '14 at 01:54
  • You might be looking for the mixin pattern. It's easier to understand than prototypes, and allows for selection of specific properties. – Bergi Jul 08 '14 at 01:55
  • @jt0dd: No. It's a constructor. (which has a prototype, but you haven't used that). – Bergi Jul 08 '14 at 01:55
  • @Bergi I need to use prototypes. correct me if I'm wrong, but `lamborghi = new car("red")` is an instance of the `car` prototype. –  Jul 08 '14 at 01:55
  • Whoa. Please don't learn from w3schools. Those paragraphs are horrible, and apparently confusing to newbies (if they're not just completely wrong). You might want to check out http://eloquentjavascript.net/chapter8.html or http://stackoverflow.com/q/572897/1048572 – Bergi Jul 08 '14 at 01:58

3 Answers3

1

It sounds like you just want to add to the prototype of car? Or do you want to add it to the prototype of everything you create (ill-advised)?

car.prototype.logDependencies = function(){ return 'whatever'; }

var lamborghini = new car('red');

lamborghini.logDependencies(); // whatever 

Here's how you get a decent JavaScript developer angry:

Object.prototype.logDependencies = function(){ return "I just don't give a..."; }

var anything = new Object();

anything.logDependencies(); // I just don't give a...

To clarify, the reason that the above is bad is explained in the article you posted:

The problem with the object function is that it is global, and globals are clearly problematic. The problem with Object.prototype.[someMethod] is that it trips up incompetent programs, and it can produce unexpected results when [someMethod] is overridden.

Having read your comments, it sounds to me as if you are after a magic wand of sorts. Perhaps you are coming from a Java world? Or an Actionscript 3 world? Where types are stronger, and inheritance is classical. JavaScript is a pretty malleable language, and we've all managed to squeeze aspects of other languages out of it in some-form-or-other. But if what you're asking JavaScript to do is to enforce some sort of class-based inheritance system without you calling a few methods and declaring a few variables here-and-there, then you're in for disappointment.

I suggest you read Douglas Crockford's other article, in which he explains how useful JavaScript's prototypal system is - and hints at how to leverage classical inheritence-like features.

shennan
  • 10,798
  • 5
  • 44
  • 79
  • Please remove the "make angry" thing from your answer, it probably will only confuse the OP who hasn't really grasped the prototype concept. At least you'd need to state *why* this is wrong. – Bergi Jul 08 '14 at 02:00
  • Nonono. Lets say I want to build a framework that is very object oriented, and utilizes dependency injection. I want to build a prototype that inherits methods from a "parent" prototype. All of the prototypes created *through the framework* utilizing the augmented prototype creation should inherit methods such as `findDependencies()` and other related methods, facilitating dependency injection in each component of the app's engine. –  Jul 08 '14 at 02:01
  • [Douglas Crockford talks about it](http://javascript.crockford.com/prototypal.html) - True Prototypical inheritance. –  Jul 08 '14 at 02:03
  • @jt0dd: Prototype is the inheritance mechanism, like `:` in c++ or `extends` in java. Instead of fixating on prototype ask the actual question you want to ask: what functionality do you want? – slebetman Jul 08 '14 at 02:48
0

If you want something along the lines of inheritance where car has all the functions that parent has prototyped, then you can use:

car.prototype = Object.create(parent.prototype);

Basically, Object.create(obj) returns a new object whose prototype is set to obj. All instances of car had their prototype set to car.prototype. Thus they will have access to parent's functions via the prototype chain.

Wio
  • 1,197
  • 10
  • 9
  • I'm thinking along the lines of a prototype that creates a new prototyping method (or a sub-prototype) which inherits certain methods from it's prototype, and passes them on to any object prototypes that it facilitates. –  Jul 08 '14 at 02:07
  • 1
    Your example code is very open ended and all the answers provided fit your specifications, yet you are not satisfied. You need to come up with an example that better illustrates what you are trying to accomplish. – Wio Jul 08 '14 at 02:19
  • my examples are open ended because for me to create a good example, I'd have to already know how to do what I'm asking... Look at the emphasized area of the article appended. Perhaps you can help me word my question in a better way, if you see my goal. –  Jul 08 '14 at 02:24
  • 1
    @jt0dd - why not write some pseudocode. That is, write code that is deliberately not working but has the exact syntax/structure you want so people can tell you how to get the functionality you want. In other words, stop using "prototype" in your example because it confuses the mechanism of inheritance with the behavior of inheritance you want. – slebetman Jul 08 '14 at 02:45
0

You could always use mixins for sharing functionality. For example:

var mixinLogger = (function () {
    return function (that) {
        that.logDependencies = logDependencies;
        return that;
    };

    function logDependencies() {
        for (var key in this)
            if (this.hasOwnProperty(key) &&
                this[key] instanceof Dependency)
                console.log("Dependency: " + key);
    }
}());

You use it as follows:

function Dependency(data) {
    this.data = data;
}

function Car(color) {
    this.color = new Dependency(color);
}

mixinLogger(Car.prototype);

The advantage of using mixins is that they are composable. For example if you have two mixins (mixinA and mixinB) then you can chain them as follows:

mixinA(mixinB(Something.prototype));

You could even create a new mixin which is composition of the two:

function compose() {
    var fs = arguments;
    var length = fs.length;

    return function (x) {
        var index = length;
        while (index > 0) x = fs[--index](x);
        return x;
    };
}

var mixinC = compose(mixinA, mixinB);

In fact you could compose as many mixins as you wish, to create new mixins.

If you want to learn more then you should read the blog post "A fresh look at JavaScript Mixins".

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299