10

我想在使用模块模式的情况下复制实例化可调用类。

以下是我对此的最佳尝试。但是,它使用__proto__我不确定。这可以在没有 的情况下完成__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

}
4

1 回答 1

7

代理人

如果您反对使用__proto__或与之相关的任何东西,但仍想要可继承性,则可以使用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;
}

优点

  • 保持可继承性。
  • 不涉及传统的原型链。
  • ES6 草案

缺点

  • 目前仅支持 Firefox >=24。

设置原型

如果缺少对代理的支持让您感到沮丧,您可以尝试使用setPrototypeOfpolyfill。

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

优点

  • 可能在现在和将来工作得最好。
  • ES6 草案

缺点

  • 通过 polyfill使用非标准__proto__,并且需要跨您想要支持的引擎/浏览器进行测试。
  • setPrototypeOf目前没有在任何浏览器中实现。

复制

这是功能最少的最简单的解决方案,但它保证几乎可以在任何地方工作。创建一个新函数并将对象的属性克隆到它上面。

function ObjectCallable(cls) {
    var f = function() { return f.__call__.apply(f, arguments); }, k;
    for (k in cls) {
        f[k] = cls[k];
    }
    return f;
}

优点

  • 几乎可以在任何地方工作。

缺点

  • 不维护任何类似的继承或原型结构。

结论

你想要__call__在 JavaScript 中复制 Python 的功能需要更多时间,因为 ES6 开发并在更多引擎中实现,或者依赖于非标准功能,例如__proto__.

于 2013-11-16T18:50:00.970 回答