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 } ```

Original source

Related problems