Replicating python's __call__ in javascript?
javascript, prototype-programming
Solution
Proxy
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;
}
Pros
- Maintains inheritability.
- Does not involve a traditional prototype chain.
- ES6 draft.
Cons
- Currently supported only by Firefox >=24.
setPrototypeOf
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;
}
Pros
- Likely to work the best right now and in the future.
- ES6 draft.
Cons
- Makes use of the non-standard `__proto__` through the polyfill and will require testing across the engines/browsers you want to support.
- `setPrototypeOf` is not currently implemented in any browser.
copy
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;
}
Pros
- Works virtually everywhere.
Cons
- Does not maintain any semblance of an inheritance or prototype structure whatsoever.
Conclusion
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__`.
Problem
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 } ```