Proxymi ·
Proxy-based multiple inheritance for JavaScript. Without mixins.
Proxymi is a library that adds support for dynamic multiple inheritance to JavaScript with a simple syntax. “Dynamic” means that changes to base classes at runtime are reflected immediately in all derived classes just like programmers would expect when working with single prototype inheritance.
Proxymi uses proxies along with other relatively new language features to provide multiple inheritance. Some of these features are not yet well supported in all browsers. As of today, Proxymi runs in current versions of Chrome, Firefox, Safari[notes], Opera and in Node.js. As JavaScript support in other browsers improves, Proxymi will start to run in those browsers, too.
Features
- C++ style multiple inheritance
- Works in Node.js and in most browsers
- Full TypeScript support
- Zero dependencies
- Qualified or unqualified access to all base class features
- constructors
- methods, getters and setters – both static and nonstatic
- value properties on base classes and base instance prototypes
in
,instanceof
andisPrototypeOf
integration
Setup Instructions
In the Browser
To use Proxymi in your project, download proxymi.js or proxymi.min.js from GitHub and include it in your HTML file.
Alternatively, you can hotlink the current stable version using a CDN of your choice.
In Node.js
If you are using Node.js 8 or later, you can install Proxymi with npm.
npm install proxymi
Then you can use it in your code.
;
Usage
Inherit from more than one base class
For example, declare a derived class ColoredCircle
that inherits from both base classes Circle
and ColoredObject
.
{ this; thisradius = radius; } { return thisradius * 2; } { thisradius = diameter / 2; } thiscenterX = centerX; thiscenterY = centerY; return `circle with center (, ) and radius `; static { return obj1color === obj2color; } { thiscolor = color; } { console; } { return ` object`; } extends // Base classes in a comma-separated list // Add methods here.
Use methods and accessors from all base classes
const c = ; c;cradius = 1;ccolor = 'red';console; // 42, 31console; // 2c; // "painting in red"
instanceof
works just like it should
const c = ; console; // trueconsole; // trueconsole; // trueconsole; // trueconsole; // false
In pure JavaScript, the expression
Bprototype instanceof A
determines if A
is a base class of class B
.
Proxymi takes care that this test still works well with multiple inheritance.
console; // trueconsole; // trueconsole; // falseconsole; // trueconsole; // false
isPrototypeOf
works fine, too
const c = ; console; // trueconsole; // trueconsole; // trueconsole; // trueconsole; // false
console; // trueconsole; // trueconsole; // falseconsole; // falseconsole; // true
Invoke multiple base constructors
Use arrays to group together parameters for each base constructor in the derived class constructor.
extends { super centerX centerY radius // Circle constructor params color // ColoredObject constructor params ; }
If you prefer to keep parameter lists associated to their base classes explicitly without relying on order, there is an alternative syntax.
extends { super super: ColoredObject arguments: color super: Circle arguments: centerX centerY radius ; }
There is no need to specify an array of parameters for each base constructor. If the parameter arrays are omitted, the base constructors will still be invoked without parameters.
extends { super; // Base constructors invoked without parameters thiscenterX = 0; thiscenterY = 0; thisradius = 1; thiscolor = 'white'; }
Use base class methods and accessors
As usual, the keyword super
invokes a base class method or accessor when used inside a derived
class.
extends console; super;
If different base classes include a method or accessor with the same name, the syntax
supermethodOrAccessor
can be used to make the invocation unambiguous.
extends // Using method toString of base class Circle const circleString = super; return ` in `;
Static methods and accessors are inherited, too
ColoredCircle
same as
ColoredObject
Dynamic base class changes
If a property in a base class is added, removed or modified at runtime, the changes are immediately reflected in all derived classes. This is the magic of proxies.
const c = ; Circleprototype console;c; // print "foo"
Compatibility
Proxymi was successfully tested in the following browsers / JavaScript engines.
- Chrome 54+
- Firefox 51+
- Safari 11 (Partial support. See notes below.)
- Opera 41+
- Node.js 8+
Because of poor ECMAScript compliance, Safari accepts non-constructor functions (such as arrow
functions, generators, etc.) as arguments to
classes
,[issue] although it does
not allow instantiating classes derived from such functions.
Also, Safari does not throw a TypeError
when attempting to assign to a read-only property of a
Proxymi class or object in strict
mode.[issue]
In the current version of Edge, the JavaScript engine Chakra has
a serious bug that can produce incorrect
results when the instanceof
operator is used with bound functions after Proxymi has been loaded.
For this reason it is recommended not to use Proxymi in Edge as long as this issue persists.