extensible-function
Version:
An extensible ES6 function with idiomatic inheritance and various other benifits
92 lines (77 loc) • 3.57 kB
Markdown
An extensible ES6 function with idiomatic inheritance and various other benifits:
[](https://travis-ci.org/Aldlevine/extensible-function)
```bash
npm install --save extensible-function
```
- When extending `ExtensibleFunction`, the code is idiomatic of extending any ES6 class (no, mucking about with pretend constructors or proxies).
- The prototype chain is retained through all subclasses, and `instanceof` / `.constructor` return the expected values.
- `.bind()` `.apply()` and `.call()` all function as expected. This is done by overriding these methods to alter the context of the "inner" function as opposed to the `ExtensibleFunction` (or it's subclass') instance.
- `.bind()` returns a new instance of the functions constructor (be it `ExtensibleFunction` or a subclass). It uses `Object.assign()` to ensure the properties stored on the bound function are consistent with those of the originating function.
- Closures are honored, and arrow functions continue to maintain the proper context.
- The "inner" function is stored via a `Symbol`, which is obfuscated by the module.
## ExtensibleFunction
#### Example of extending `ExtensibleFunction`
```javascript
const ExtensibleFunction = require('extensible-function');
// OR //
import ExtensibleFunction from 'extensible-function';
// Lets extend our `ExtensibleFunction` into an `ExtendedFunction`
class ExtendedFunction extends ExtensibleFunction {
constructor (fn, ...args) {
// Just use `super()` like any other class
// You don't need to pass ...args here, but if you used them
// in the super class, you might want to.
super(fn, ...args);
// Just use `this` like any other class. No more messing with fake return values!
let [constructedPropertyValue, ...rest] = args;
this.constructedProperty = constructedPropertyValue;
}
}
```
```javascript
let fn = new ExtendedFunction(function (x) {
// Add `this.y` to `x`
// If either value isn't a number, coax it to one, else it's `0`
return (this.y>>0) + (x>>0)
}, "I'm a constructed property value");
fn.additionalProperty = "I'm an additional property value";
```
```javascript
fn instanceof Function; // true
fn instanceof ExtensibleFunction; //true
fn instanceof ExtendedFunction; //true
fn.bind() instanceof Function; //true
fn.bind() instanceof ExtensibleFunction; //true
fn.bind() instanceof ExtendedFunction; //true
fn.constructor == ExtendedFunction; //true
fn.constructedProperty == "I'm a constructed property value"; //true
fn.additionalProperty == "I'm an additional property value"; //true
fn.constructedProperty == fn.bind().constructedProperty; //true
fn.additionalProperty == fn.bind().additionalProperty; //true
fn() == 0; //true
fn(10) == 10; //true
fn.apply({y:10}, [10]) == 20; //true
fn.call({y:10}, 20) == 30; //true
fn.bind({y:30})(10) == 40; //true
```
The module also provides a convenient constructor which binds a function to itself. Yeah, it sounds weird but the benefit is that calls to these functions have their `this` set to themselves.
```javascript
class BoundExtendedFunction extends ExtensibleFunction.Bound {
constructor (fn, x) {
super(fn);
this.x = x;
}
}
let bfn = new BoundExtendedFunction(function(y){
return this.x + y;
}, 100);
bfn(42); // 142
bfn.x = 0;
bfn(42); // 42
```