// 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__
是非标准的且已弃用。
我应该如何继承原型(prototype)创建一个对象,但让该对象成为一个函数。
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-discuss 线程中所述,存在一个 ES:strawman <|
允许这样做的原型(prototype)运算符。
让我们看看使用 <|
会是什么样子
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
最佳答案
我希望我理解正确。
我相信您想要一个既是预定义原型(prototype)(是的,类,只是不是经典类)又可直接调用的实例的仿函数?正确的?如果是这样,那么这就非常有意义并且非常强大和灵活(尤其是在像 JavaScript 这样的高度异步环境中)。 遗憾的是,如果不操纵 __proto__
,就无法在 JavaScript 中优雅地完成它。您可以通过分解出一个匿名函数并将所有引用复制到所有方法(这似乎是您前进的方向)以充当代理类来实现。这样做的缺点是...
- 就运行时间而言成本非常高。
(functorObj instanceof MyClass)
永远不会是true
。- 属性将无法直接访问(如果它们都是通过引用分配的,那将是另一回事,但是基元是通过值分配的)。这可以通过访问器通过
defineProperty
或在必要时简单地命名访问器方法来解决(看起来这就是你要找的,只需将所有属性添加到带有defineProperty
的仿函数> 如果您不需要跨引擎支持/向后兼容性,则通过 getters/setters 而不是仅使用函数。 - 您可能会遇到最终原生原型(prototype)(如 Object.prototype 或 Array.prototype [如果您继承了它])可能无法按预期运行的边缘情况。
- 调用
functorObj(someArg)
将总是使this
上下文成为对象,无论它是否被称为functorObj.call (someOtherObj, someArg)
(虽然方法调用不是这种情况) - 因为仿函数对象是在请求时创建的,它会被及时锁定并且操作初始原型(prototype)不会影响分配的仿函数对象,就像普通对象会受到影响一样(修改 MyClass.prototype 不会影响任何仿函数对象和反之亦然)。
不过,如果您轻轻地使用它,这些应该都不是什么大问题。
在你的类原型(prototype)中定义类似...
// 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.
您甚至可以链式绑定(bind)无数其他对象/函数/等,直到奶牛回家。只需稍微重构代理调用即可。
希望对您有所帮助。哦,当然,您可以更改工厂流程,以便在不使用 new
运算符的情况下调用构造函数,然后实例化一个新对象并返回仿函数对象。无论您喜欢什么(您当然也可以通过其他方式做到这一点)。
最后,要让任何函数以更优雅的方式成为仿函数的执行运算符,只需将代理函数设为 Function.prototype
的方法,并将要包装的对象传递给它如果你想做类似的事情(当然你必须将 templateFunction
与 this
和 this
与参数交换)...
var functor = (function() { /* something */ }).asFunctor(aobj);
关于javascript - 我如何继承 javascript 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7539148/