2015-07-12 4 views
0

Я знаю, что на нескольких языках, таких как C++, вы можете создавать классы с множественным наследованием (или, по крайней мере, имитировать его с помощью таких интерфейсов, как Java). В JavaScript можно определить интерфейс, который может быть реализован в классе? Если да, то каким будет лучший способ приблизиться к этому, в идеале, каким-то образом включив цепочку прототипов. Будет ли ниже работать, или есть лучший способ?Определение интерфейса в JavaScript через цепочку прототипов

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);

+0

Нет, вы не можете использовать цепочку прототипов для множественного наследования. – Bergi

+0

Также обратите внимание на 'foo = Object.create (Foo.prototype);', 'foo instanceof Foo; // true' vs 'foo = Object.create (Foo);', 'foo instanceof Foo; // false. –

+0

@PaulS. Исправлено, спасибо. –

ответ

1

Используя что-то вроде underscore.js, вы можете создать новый объект на основе двух независимых прототипов и использовать его в качестве прототипа. В этом примере свойства/методы, определенные в obj2, будут перезаписывать любой объект obj1 в объекте результата.

function IAmMulti(){ 

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

Вот пример того, что: JavaScript inheritance with _.extend()

+0

Это кажется разумным.Однако в этом случае я предполагаю, что экземпляр 'IAmMulti' не будет экземпляром либо' Obj1', либо 'Obj2' правильным? Я не критикую ваш ответ. Я просто убедился, что лучше понимаю смысл. –

+1

Справа. Это будет только экземпляр нового типа. – DarthDerrr

+1

@DarthDerrr Извините, но что продлевает прототип одного объекта на другой объект, связано с концепцией интерфейсов в объектно-ориентированном программировании? Интерфейс - это описание всех методов, которые должны иметь объект типа ** T **. Как вы можете и полностью убедиться, что объект javascript реализует интерфейс, чтобы действовать как объект типа ** T **, когда нет необходимости реализации в * duck typing *? – DavidDomain

1

Вы не можете наследовать более 1 прототип на любом уровне (вы можете иметь стек наследования, хотя), и интерфейсы не имеют никакого значения, так как браузер динамический язык и весь цепочка прототипов выполняется поиск совпадающих имен. Нет понятия доступа к объекту через интерфейс.

+0

Я хотел бы указать, что интерфейсы имеют смысл в JavaScript, особенно при реализации на уровне. Например, на [этой странице MDN] (https://developer.mozilla.org/en-US/docs/Web/API/Element), '' Element' nherits свойства от родителя 'Node' и собственного родителя , «EventTarget» и реализует функции «ParentNode», «ChildNode», «NonDocumentTypeChildNode» и «Animatable». » Это 4 разных интерфейса, поэтому он имеет смысл в JavaScript, даже если вы говорите, что это невозможно сделать через цепочку прототипов. –

+1

@PatrickRoberts - Во-первых, это все объекты DOM, а не JavaScript. Во-вторых, вы не можете получить доступ к объектам javascript через интерфейсы. У вас либо есть доступ («адрес») к объекту, и он «полностью открыт», либо нет – Amit

+0

, что не так с кодом в моем вопросе, чтобы создать что-то, что действует как интерфейс, даже если это не обязательно экземпляр этого? –

0

В JavaScript вы можете определить до одного объекта который будет наследоваться вашей объекта. Это Наследование объекта также наследуется вашим объектом и т. Д. В длинной цепочке.

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 

Вы всегда можете применить конструктор к Object который не является экземпляром так не будет наследовать от этого конструктора. Только будьте осторожны, конструктор не принимает существования унаследованных методов и т.д.,

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

Если вы хотите, чтобы написать метод оболочки, чтобы делать вещи, то вы можете использовать почти любой объект в любой контекст

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"