├── README.md ├── example.js └── inherit.js /README.md: -------------------------------------------------------------------------------- 1 | Multiple Inheritance Implemented in JavaScript 2 | ============================= 3 | 4 | What is multiple inheritance? http://en.wikipedia.org/wiki/Multiple_inheritance 5 | 6 | What does it mean in JavaScript? : 7 | Having 3 classes "Name" , "Age" and "Place" create an object "person" which should inherit from all three constructors. It should have all the prototype properties of each constructor and 'own' properties from each constructor. Also "person" should be an instance of all 3. Any instances of individual constructors should not be instances of other constructors. Dynamically adding prototype properties to any constructor should reflect for "person" object as well 8 | 9 | 10 | Why? Because it can be done. Remember always bet on JS! 11 | 12 | Live Example: Checkout output in Console. 13 | 14 | JSFiddle : http://jsfiddle.net/adityapunjani/uYhPa/ 15 | 16 | JSBIN : http://jsbin.com/ESiwimEm/1/edit 17 | 18 | Usage : Use the function "inherit" in inherit.js file or include the file. 19 | 20 | Inherit function takes n Constructors to extend from as arguments. 21 | 22 | Syntax inherit(Constructor1[, Constructor2[, ...]]) 23 | Where each argument is a function or an object. 24 | 25 | If your constructor function does not take any arguments, pass the function itself to the "inherit" function as an argument. Ex var x = inherit(p,q,n) where p,q,n are constructor functions 26 | 27 | If you want to pass arguments to a constructor function, create an an object with "Constructor" (capital C) key defined as the constructor function and "Arguments" (capital A) key defined as an array of all arguments the constructor function takes in order. 28 | Ex inherit(x, {"Constructor" : y, "Arguments" : [1,"asd",true]}, z) where x & z are constructor functions and the 2nd argument is an object with "Constructor" key as constructor function x and "Arguments" key as array of all arguments the constructor function takes. 29 | 30 | Implemented Object.instanceOf to replace the "instanceof" operator so as to satisfy the instance of conditions. 31 | 32 | Reflecting dynamically added prototype properties is implemented using Object.observe and will only work for latest chrome browser whith experimental JavaScript flag turned on in chrome://flags/ or any other browser that supports ES6 33 | 34 | Todo Implement Object.observe polyfill for ES5. 35 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | //Example : Having 3 classes "Name" , "Age" and "Place" create an object "person" which should inherit from all three constructors. 2 | //It should have all the prototype properties of each constructor and 'own' properties of each constructor. 3 | //Also "person" should be an instance of all 3. Any instances of individual constructors should not be instances of other constructors. 4 | 5 | //Implemented Object.instanceOf to replace the "instanceof" operator so as to satisfy the above conditions. 6 | 7 | //Dynamically adding prototype properties to any constructor should reflect for "person" object as well. 8 | //This is implemented using Object.observe and will only work for latest chrome browser whith experimental JavaScript flag turned on in chrome://flags/ or any other browser that supports ES6 9 | 10 | //Todo Implement Object.observe polyfill for ES5. 11 | 12 | Object.prototype.instanceOf = function (obj) { 13 | if(this instanceof obj) return true; 14 | if (this.constructor === obj) return true; 15 | if (this.constructors) { 16 | for (var i = 0; i < this.constructors.length; i++) { 17 | if (this.constructors[i] === obj) return true; 18 | } 19 | } 20 | return false; 21 | }; 22 | 23 | function inherit() { 24 | function clone(to, source) { 25 | for (var key in source) { 26 | to[key] = source[key]; 27 | } 28 | } 29 | var Prev, f, from, obj, params, arg, i = 0; 30 | 31 | function copy(to, objArray) { 32 | for (i = 0; i < objArray.length; i++) { 33 | if (Object.prototype.toString.call(objArray[i]) === "[object Object]") { 34 | params = objArray[i].Arguments; 35 | arg = objArray[i].Constructor; 36 | from = new arg(); 37 | arg.apply(from, params); 38 | 39 | } else { 40 | from = new objArray[i](); 41 | } 42 | for (var prop in from) { 43 | if (from.hasOwnProperty(prop)) { 44 | to[prop] = from[prop]; 45 | } 46 | } 47 | } 48 | } 49 | 50 | f = function () {}; 51 | constructors = []; 52 | for (i = 0; i < arguments.length; i++) { 53 | 54 | 55 | arg = arguments[i].Constructor || arguments[i]; 56 | 57 | clone(f.prototype, arg.prototype); 58 | 59 | if (Object.observe) { 60 | var change = (function (a) { 61 | return function () { 62 | clone(f.prototype, a); 63 | }; 64 | })(arg.prototype); 65 | Object.observe(arg.prototype, change); 66 | } 67 | constructors.push(arg); 68 | } 69 | 70 | obj = new f(); 71 | copy(obj, arguments); 72 | obj.constructors = constructors; 73 | return obj; 74 | } 75 | 76 | var NameConstructor = function n() { 77 | this.printName = function () { 78 | console.log("NameConstructor Method logging name : " + this.name); 79 | }; 80 | }; 81 | NameConstructor.prototype.name = "aditya"; 82 | 83 | var AgeConstructor = function a(age) { 84 | this.age = age || 0; 85 | this.printName = function () { 86 | console.log("AgeConstructor Method logging age : " + this.age); 87 | }; 88 | }; 89 | 90 | var PlaceConstructor = function p() {}; 91 | PlaceConstructor.prototype.place = "Bangalore"; 92 | 93 | //call inherit to create a new instance of all three constructors. 94 | var person = inherit(NameConstructor, { 95 | "Constructor": AgeConstructor, 96 | "Arguments": [21] 97 | }, 98 | PlaceConstructor); 99 | 100 | 101 | console.log("Is person instance of NameConstructor? : " + person.instanceOf(NameConstructor)); 102 | console.log("Is person instance of AgeConstructor? : " + person.instanceOf(AgeConstructor)); 103 | console.log("Is person instance of PlaceConstructor? : " + person.instanceOf(PlaceConstructor)); 104 | 105 | console.log("Log person.name: " + (person.name)); 106 | console.log("Log person.age: " + (person.age)); 107 | console.log("Log person.place: " + (person.place)); 108 | 109 | console.log("Creating instance of NameConstructor as n"); 110 | var n = new NameConstructor(); 111 | console.log("Is n instance of NameConstructor? : " + n.instanceOf(NameConstructor)); 112 | console.log("Is n instance of AgeConstructor? : " + n.instanceOf(AgeConstructor)); 113 | console.log("Is n instance of PlaceConstructor? : " + n.instanceOf(PlaceConstructor)); 114 | 115 | console.log("Creating instance of AgeConstructor as a"); 116 | var a = new AgeConstructor(); 117 | console.log("Is a instance of NameConstructor? : " + a.instanceOf(NameConstructor)); 118 | console.log("Is a instance of AgeConstructor? : " + a.instanceOf(AgeConstructor)); 119 | console.log("Is a instance of PlaceConstructor? : " + a.instanceOf(PlaceConstructor)); 120 | 121 | console.log("Creating instance of PlaceConstructor as p"); 122 | var p = new PlaceConstructor(); 123 | console.log("Is p instance of NameConstructor? : " + p.instanceOf(NameConstructor)); 124 | console.log("Is p instance of AgeConstructor? : " + p.instanceOf(AgeConstructor)); 125 | console.log("Is p instance of PlaceConstructor? : " + p.instanceOf(PlaceConstructor)); 126 | -------------------------------------------------------------------------------- /inherit.js: -------------------------------------------------------------------------------- 1 | //Inherit function takes n Constructors to extend from as arguments. By @adityapunjani 2 | 3 | //Syntax inhert(Constructor1[, Constructor2[, ...]]) 4 | //Where each argument is function or an object. 5 | 6 | //If your constructor function does not take arguments, pass the function itself to the "inherit" function as an argument. Ex var x = inherit(p,q,n) where p,q,n are constructor functions 7 | 8 | //If you want to pass arguments to a constructor function, create an an object with "Constructor" (capital C) key defined as the constructor function and "Arguments" (capital A) key defined as an array of all arguments the constructor function takes in order. 9 | //Ex inherit(x, {"Constructor" : y, "Arguments" : [1,"asd",true]}, z) 10 | //where x & z are constructor functions and the 2nd argument is an object with "Constructor" key as constructor function x and "Arguments" key as array of all arguments the constructor function takes. 11 | 12 | 13 | 14 | Object.prototype.instanceOf = function (obj) { 15 | if(this instanceof obj) return true; 16 | if (this.constructor === obj) return true; 17 | if (this.constructors) { 18 | for (var i = 0; i < this.constructors.length; i++) { 19 | if (this.constructors[i] === obj) return true; 20 | } 21 | } 22 | return false; 23 | }; 24 | 25 | function inherit() { 26 | function clone(to, source) { 27 | for (var key in source) { 28 | to[key] = source[key]; 29 | } 30 | } 31 | var Prev, f, from, obj, params, arg, i = 0; 32 | 33 | function copy(to, objArray) { 34 | for (i = 0; i < objArray.length; i++) { 35 | if (Object.prototype.toString.call(objArray[i]) === "[object Object]") { 36 | params = objArray[i].Arguments; 37 | arg = objArray[i].Constructor; 38 | from = new arg(); 39 | arg.apply(from, params); 40 | 41 | } else { 42 | from = new objArray[i](); 43 | } 44 | for (var prop in from) { 45 | if (from.hasOwnProperty(prop)) { 46 | to[prop] = from[prop]; 47 | } 48 | } 49 | } 50 | } 51 | 52 | f = function () {}; 53 | constructors = []; 54 | for (i = 0; i < arguments.length; i++) { 55 | 56 | 57 | arg = arguments[i].Constructor || arguments[i]; 58 | 59 | clone(f.prototype, arg.prototype); 60 | 61 | if (Object.observe) { 62 | var change = (function (a) { 63 | return function () { 64 | clone(f.prototype, a); 65 | }; 66 | })(arg.prototype); 67 | Object.observe(arg.prototype, change); 68 | } 69 | constructors.push(arg); 70 | } 71 | 72 | obj = new f(); 73 | copy(obj, arguments); 74 | obj.constructors = constructors; 75 | return obj; 76 | } 77 | 78 | //Implemented Object.instanceOf to replace the "instanceof" operator so as to satisfy instanceof conditions. 79 | 80 | //Dynamically adding prototype properties to any constructor should reflect for inherited object as well. 81 | //This is implemented using Object.observe and will only work for latest chrome browser whith experimental JavaScript flag turned on in chrome://flags/ or any other browser that supports ES6 82 | 83 | //Todo Implement Object.observe polyfill for ES5. 84 | --------------------------------------------------------------------------------