0

I know that in several languages like C++, you can create classes with multiple inheritance (or at least simulate it using interfaces like in Java). In JavaScript, is it possible to define an interface that can be implemented on a class? If so, what would be the best way to approach doing this, ideally incorporating the prototype chain somehow. Would below work, or is there a better way?

function Gizmo() {
    console.log('Gizmo constructed');
}

Gizmo.prototype.wamboozle = function () {
    console.log('wamboozle');
};

function EventEmitter() {
    console.log('EventEmitter constructed');
    this.events = {};
}

EventEmitter.prototype.on = function (name, callback) {
    this.events[name] ? this.events[name].push(callback) : (this.events[name] = [callback]);
};

EventEmitter.prototype.emit = function (name, event) {
    if (this.events[name]) {
        this.events[name].forEach(function (callback) {
            callback(event);
        });
    }
};

// set up inheritance and implementation

// maybe this could be a possibility?
Doohickey.prototype = Object.create(Gizmo.prototype);

Object.getOwnPropertyNames(EventEmitter.prototype).forEach(function (member) {
    Doohickey.prototype[member] = EventEmitter.prototype[member];
});

function Doohickey() {
    console.log('Doohickey constructed');
    Gizmo.call(this); // initialize base class
    EventEmitter.call(this); // initialize interface
}

Doohickey.prototype.turlywoops = function () {
    console.log('turlywoops');
};

var myOwnDoohickey = new Doohickey();

// member function works
myOwnDoohickey.turlywoops();

// inherited member function works
myOwnDoohickey.wamboozle();

// interface member functions work
myOwnDoohickey.on('finagle', function (trick) {
    console.log(trick);
});

myOwnDoohickey.emit('finagle', {
    hello: 'world!'
});

// both true
console.log(myOwnDoohickey instanceof Doohickey);
console.log(myOwnDoohickey instanceof Gizmo);

// don't mind if this isn't necessarily true, though it would be nice
console.log(myOwnDoohickey instanceof EventEmitter);

2
  • No, you cannot use the prototype chain for multiple inheritance. Commented Jul 12, 2015 at 21:58
  • Please also be aware foo = Object.create(Foo.prototype);, foo instanceof Foo; // true vs foo = Object.create(Foo);, foo instanceof Foo; // false. Commented Jul 12, 2015 at 22:08

3 Answers 3

1

Using something like underscore.js, you could create a new object based on two unrelated prototypes and use it as a prototype. In this example, properties/methods defined in obj2 will overwrite any in obj1 in the result object.

function IAmMulti(){

}
IAmMulti.prototype=_.extend(_.clone(Obj1.prototype),_.clone(Obj2.prototype));

Here's an example of that: JavaScript inheritance with _.extend()

Sign up to request clarification or add additional context in comments.

4 Comments

This seems reasonable. However in this case, I'm guessing an instance of IAmMulti would not be an instance of either Obj1 or Obj2 correct? I'm not critiquing your answer I'm just making sure I understand the implication better.
Right. It will only be an instance of the new type.
@DarthDerrr Sorry, but what does extending the prototype of one object onto another object has to do with the concept of interfaces in object oriented programming? An interface is a description of all methods that an object must have to be of type T. How can you possibly and entirely ensure that a javascript object implements an interface to act like an object of type T, when there is no requirement of implementation in duck typing ?
I suppose it depends on the use case really. If one simply wants to make sure an object prototype has everything from two different prototypes, without needing to check membership of an interface, what I proposed works. I've done it similarly in my projects and haven't had any problems with it. If an object is an instance of the new type, I assume it works.
1

You can't inherit more than 1 prototype at any level (you can have a stack of inheritance though), and interfaces have no meaning since javascript is a dynamic language and the entire prototype chain is searched for matching names. There's no notion of accessing an object through an interface.

3 Comments

I'd like to point out that interfaces do have meaning in JavaScript, particularly at the native level implementation. For example on this page of MDN, "Element nherits properties from its parents Node, and its own parent, EventTarget, and implements those of ParentNode, ChildNode, NonDocumentTypeChildNode, and Animatable." That's 4 different interfaces, so it does have meaning in JavaScript even if you say it can't be done via the prototype chain.
@PatrickRoberts - First, these are all DOM objects, not JavaScript. Second, you can't access javascript objects through interfaces. You either have access ("address of") to an object, and it's "fully exposed", or you don't
what's wrong with the code in my question to create something that acts like an interface, even if it's not necessarily an instance of it?
0

In JavaScript you can define up to one Object which will be inherited by your Object. That Object's inheritance is also inherited by your object, etc, in a long chain.

function Foo() {
    this.fooThisProp = 'tfoo';
}
Foo.prototype = Object.create(null);
Foo.prototype.fooProtoProp = 'pfoo';

function Bar() {
    Foo.call(this);
    this.barThisProp = 'tbar';
}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.barProtoProp = 'pbar';

function Baz() {
    Bar.call(this);
    this.bazThisProp = 'tbaz';
}
Baz.prototype = Object.create(Bar.prototype);
Baz.prototype.bazProtoProp = 'pbaz';

var obj = new Baz();
obj; // {barThisProp: "tbar", bazThisProp: "tbaz", fooThisProp: "tfoo"}
obj.bazProtoProp; // "pbaz"
obj.barProtoProp; // "pbar"
obj.fooProtoProp; // "pfoo"

obj instanceof Baz; // true
obj instanceof Bar; // true
obj instanceof Foo; // true

You could always apply a constructor to an Object which isn't an instance so wouldn't inherit from that constructor. Just be careful the constructor doesn't assume the existance of inherited methods etc,

var fizz = {};
Bar.call(fizz);
fizz; // {barThisProp: "tbar", fooThisProp: "tfoo"}
fizz.barProtoProp; // undefined
fizz.fooProtoProp; // undefined
fizz instanceof Bar; // false
fizz instanceof Foo; // false

If you want to write a method wrapper to do things then you can use pretty much any Object in any context

function Buzz() {}
Buzz.prototype = Object.create(null); // Buzz separate from Foo, Bar, Baz
Buzz.prototype.bazLook = function (key) {
    return Baz.prototype[key]; // or do something else with the value
}

var buzz = new Buzz();
buzz.bazLook('fooProtoProp'); // "pfoo"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.