我如何inheritanceJavaScript的function?
// Don't break the function prototype. // pd - https://github.com/Raynos/pd var proto = Object.create(Function.prototype, pd({ "prop": 42 })); var f = function() { return "is a function"; }; f.__proto__ = proto; console.log(f.hasOwnProperty("prop")); // false console.log(f.prop); // 42 console.log(f()); // "is a function"
.__proto__
是非标准的,不推荐使用。
我应该如何inheritance原型创build一个对象,但该对象是一个函数。
Object.create
返回一个对象不是一个函数。
new Constructor
返回一个对象不是一个函数。
动机: – 跨浏览器finherit
var finherit = function (parent, child) { var f = function() { parent.apply(this, arguments); child.apply(this, arguments); }; f.__proto__ = parent; Object.keys(child).forEach(function _copy(key) { f[key] = child[key]; }); return f; };
我不相信这是可能的,所以我们应该提出一个Function.create
到es-discuss邮件列表
/* Creates a new function whose prototype is proto. The function body is the same as the function fbody. The hash of propertydescriptors props is passed to defineproperties just like Object.create does. */ Function.create = (function() { var functionBody = function _getFunctionBody(f) { return f.toString().replace(/.+\{/, "").replace(/\}$/, ""); }; var letters = "abcdefghijklmnopqrstuvwxyz".split(""); return function _create(proto, fbody, props) { var parameters = letters.slice(0, fbody.length); parameters.push(functionBody(fbody)); var f = Function.apply(this, parameters); f.__proto__ = proto; Object.defineProperties(f, props); return f; }; })();
相关的es讨论邮件
正如es-discuss线程中提到的,存在一个ES:strawman <|
原型操作符,这将允许这一点。
让我们来看看使用<|
是什么样子
var f1 = function () { console.log("do things"); }; f1.method = function() { return 42; }; var f2 = f1 <| function () { super(); console.log("do more things"); } console.log(f1.isPrototypeOf(f2)); // true console.log(f2()); // do things do more things console.log(f2.hasOwnProperty("method")); // false console.log(f2.method()); // 42
我希望我能理解这个权利。
我相信你想要一个函数既是一个预定义的原型(是的,一个类,只是不是一个经典的类)的实例,以及直接可调用? 对? 如果是这样,那么这是非常有意义的,而且非常强大和灵活(特别是在像JavaScript这样的高度asynchronous的环境中)。 可悲的是没有办法在JavaScript中优雅地做,而不处理__proto__
。 您可以通过分解一个匿名函数并将所有的引用复制到所有的方法(这似乎是您的方向)来充当代理类。 这个缺点是…
- 从运行时间来看,这是非常昂贵的。
-
(functorObj instanceof MyClass)
永远不会是true
。 - 属性不能直接访问(如果它们都是通过引用分配的话,这将是一个不同的故事,但是基元是按值赋值的)。 这可以通过
defineProperty
accessor来解决,或者如果需要的话,简单地命名访问器方法(看起来就是你要找的东西,只defineProperty
通过getter / setter把所有的属性添加到函子defineProperty
,而不是只是函数,如果你不需要跨引擎支持/向后兼容)。 - 你很可能遇到最终本地原型(如Object.prototype或Array.prototype [如果你正在inheritance])可能无法按预期运行的边缘情况。
- 调用
functorObj(someArg)
将始终使this
上下文成为对象,而不pipe它是否被称为functorObj.call(someOtherObj, someArg)
(尽pipe方法调用不是这样) - 因为functor对象是在请求时创build的,所以它会被及时locking,操纵初始原型不会影响分配的functor对象,就像普通对象会受到影响一样(修改MyClass.prototype不会影响任何functor对象,反之亦然也是如此)。
如果你轻轻地使用它,这不应该是一个大问题。
在你的类的原型定义类似…
// This is you're emulated "overloaded" call() operator. MyClass.prototype.execute = function() { alert('I have been called like a function but have (semi-)proper access to this!'); }; MyClass.prototype.asFunctor = function(/* templateFunction */) { if ((typeof arguments[0] !== 'function') && (typeof this.execute !== 'function')) throw new TypeError('You really should define the calling operator for a functor shouldn\'t you?'); // This is both the resulting functor proxy object as well as the proxy call function var res = function() { var ret; if (res.templateFunction !== null) // the this context here could be res.asObject, or res, or whatever your goal is here ret = res.templateFunction.call(this, arguments); if (typeof res.asObject.execute === 'function') ret = res.asObject.execute.apply(res.asObject, arguments); return ret; }; res.asObject = this; res.templateFunction = (typeof arguments[0] === 'function') ? arguments[0] : null; for (var k in this) { if (typeof this[k] === 'function') { res[k] = (function(reference) { var m = function() { return m.proxyReference.apply((this === res) ? res.asObject : this, arguments); }; m.proxyReference = reference; return m; })(this.asObject[k]); } } return res; };
导致的用法看起来像…
var aobj = new MyClass(); var afunctor = aobj.asFunctor(); aobj.someMethodOfMine(); // << works afunctor.someMethodOfMine(); // << works exactly like the previous call (including the this context). afunctor('hello'); // << works by calling aobj.execute('hello'); (aobj instanceof MyClass) // << true (afunctor instanceof MyClass) // << false (afunctor.asObject === aobj) // << true // to bind with a previous function... var afunctor = (new MyClass()).asFunctor(function() { alert('I am the original call'); }); afunctor() // << first calls the original, then execute(); // To simply wrap a previous function, don't define execute() in the prototype.
你甚至可以链接无数的其他对象/function等,直到奶牛回家。 只是重构代理调用了一下。
希望有所帮助。 哦,当然你可以改变工厂stream程,这样一个没有new
运算符的构造函数就会实例化一个新的对象并返回该functor对象。 不过你更喜欢(你也可以用其他方式来做)。
最后,为了使函数成为执行操作符的一个更优雅的方式,只要使代理函数为Function.prototype
的方法,并将它传递给对象来包装,如果你想做的事情就像(你会不得不交换templateFunction
与this
和当然参数)…
var functor = (function() { /* something */ }).asFunctor(aobj);