I want to replicate instantiating a callable class without using the module pattern.
The following is my best attempt at this. However, it uses __proto__
which I'm not sure about. Can this be done without __proto__
?
function classcallable(cls) {
/*
* Replicate the __call__ magic method of python and let class instances
* be callable.
*/
var new_cls = function () {
var obj = Object.create(cls.prototype);
// create callable
// we use func.__call__ because call might be defined in
// init which hasn't been called yet.
var func = function () {
return func.__call__.apply(func, arguments);
};
func.__proto__ = obj;
// apply init late so it is bound to func and not cls
cls.apply(func, arguments);
return func;
}
new_cls.prototype = cls.prototype;
return new_cls
}
If you are against using __proto__
or anything related to it but still want the inheritability, you could make use of Proxies.
var ObjectCallable_handler = {
get: function get(self, key) {
if (self.hasOwnProperty(key)) {
return self[key];
} else { return self.__inherit__[key]; }
},
apply: function apply(self, thisValue, args) {
return (self.__call__ || self.__inherit__.__call__).apply(self, args);
}
};
function ObjectCallable(cls) {
var p = new Proxy(function() { }, ObjectCallable_handler);
p.__inherit__ = cls;
return p;
}
If the lack of support for Proxies dismays you, you could try a setPrototypeOf
polyfill instead.
Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
obj.__proto__ = proto;
return obj;
}
function ObjectCallable(cls) {
var f = function() { return f.__call__.apply(f, arguments); };
Object.setPrototypeOf(f, cls);
return f;
}
__proto__
through the polyfill and will require testing across the engines/browsers you want to support.setPrototypeOf
is not currently implemented in any browser.This is the simplest solution with the least amount of functionality, but it's guaranteed to work almost anywhere. Create a new function and clone an object's properties onto it.
function ObjectCallable(cls) {
var f = function() { return f.__call__.apply(f, arguments); }, k;
for (k in cls) {
f[k] = cls[k];
}
return f;
}
What you want to do with replicating Python's __call__
functionality in JavaScript will require either more time as ES6 develops and becomes implemented in more engines or relying on non-standard functionality such as __proto__
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With