我想复制实例化一个可调用的类而不使用模块模式.
以下是我最好的尝试.但是,它使用__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 }
解决方法
代理
如果您反对使用__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 draft.
缺点
> Currently supported仅限Firefox> = 24.
setPrototypeOf
如果缺乏对Proxies的支持令您失望,您可以尝试使用setPrototypeOf
polyfill.
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 draft.
缺点
>通过polyfill使用非标准的__proto__,并且需要在您想要支持的引擎/浏览器之间进行测试.
> setPrototypeOf在任何浏览器中都是not currently implemented.
复制
这是功能最少的最简单的解决方案,但几乎可以在任何地方使用.创建一个新函数并将对象的属性克隆到其上.
function ObjectCallable(cls) { var f = function() { return f.__call__.apply(f,arguments); },k; for (k in cls) { f[k] = cls[k]; } return f; }
优点
>几乎无处不在.
缺点
>不保留任何继承或原型结构的外观.
结论
在JavaScript中复制Python的__call__功能要做的事情需要更多时间,因为ES6开发并在更多引擎中实现或依赖于非标准功能,如__proto__.