你可以使用JavaScript中的自定义原型创建函数吗? [英] Can you create functions with custom prototypes in JavaScript?

查看:86
本文介绍了你可以使用JavaScript中的自定义原型创建函数吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我不想 将方法添加到 Function.prototype 中。这样做会使它们适用于所有 函数,这不是我想要的。



在JavaScript中,您可以创建具有自定义原型的对象像这样:

 函数CustomObj(){} 
CustomObj.prototype = {};
CustomObj.prototype.sayFoo = function(){return'foo'};

var myCustomObj = new CustomObj(); // =>返回一个对象:{}
myCusomObj.sayFoo(); // => 'foo'

您也可以使用像这样的自定义原型创建类似数组的对象:

 函数CustomArr(){} 
CustomArr.prototype = [];
CustomObj.prototype.sayFoo = function(){return'foo'};

var myCustomArr = new CustomArr(); // =>返回一个有序对象:[]
myCustomArr.sayFoo(); // => 'foo'

我想要做的是使用某种构造函数来创建一个函数,它以相同的方式定制原型。但是,以下方法不起作用:

$ p $ 函数CustomFn(){}
CustomFn.prototype = function(){ };
CustomFn.prototype.sayFoo = function(){return'foo'};

var myCustomFn = new CustomFn(); // =>问题!返回一个对象:{}
myCustomFn.sayFoo(); // => 'foo'

// ^^这里应用了原型,但输出不是函数。
myCustomFn(); // => TypeError:object不是函数

那么有什么办法可以完成我想要做的事情?

UPDATE



也许还有另外一种方法可以问这个问题,这会让问题更清楚一些。



关闭关闭的想法存在问题:

 函数makeFn(){
var output = function(){/ *做一些事情* /};
output.foo = function(){/ *做一些事情* /};
返回输出;
}
var specialFn = makeFn();

实质上,这种技术给了我想要的东西。然而,问题是每次我调用 makeFn ,都必须创建 output.foo 作为完全独立的函数这占据了自己的记忆。毛。所以我可以将该方法从关闭中移出:

  var protoMethods = {
foo:function() {/ *做一些东西* /}
};
函数makeFn(){
var output = function(){/ *做一些事情* /};
for(var i in protoMethods){
Object.prototype.hasOwnProperty.call(protoMethods,i)&&
(output [i] = protoMethods [i]);
}
返回输出;
}
var specialFn = makeFn();

但是现在我每次调用 makeFn ,这会比仅仅分配 protoMethods 成为输出的原型的效率低 。所以,有了这个新的更新,任何想法?

解决方案

这确实是一个棘手的事情,比它应该是更复杂,如果语言设计得很好...



基本上,你不能在当前版本中干净地做到这一点。对象之外的对象不能被调用。



在未来的Javascript版本中,您可以使用可以定义调用处理程序的代理对象来完成此操作。但在我看来,它仍然太复杂和麻烦。

另一种方法是让你的对象成为一个真正的函数,而不是自定义对象。然后尝试设置它的 __ proto __ ,这是非标准的,但在大多数现代浏览器中可用,Opera和IE 8或更少。也可以设置它的构造函数属性来伪造 instanceof 检查......这样的黑客虽然非常棘手,但结果会有所不同

以下示例适用于我的Firefox:


 函数MyFun() {
if(!this || this == window){
return new MyFun();
}

var f = function(){
returnthanks for calling!;
}
f .__ proto__ = MyFun.prototype;
f.constructor = MyFun;

return f;


MyFun.prototype = {
foo:function(){
returnfoo:+ this();
},
__proto__:Function.prototype
};

var f = new MyFun();
alert(proto method:+ f.foo()); //试试我们的原型方法
alert(function method:+ f.call()); //尝试标准函数方法
alert(function call:+ f()); //尝试使用
alert('typeof:'+ typeof f); //功能,而不是对象。在当前的js版本中没有办法绕过它
alert('MyFun:'+(f instanceof MyFun)); // true
alert('is Function:'+(f instanceof Function)); // true

只是想补充一点,您不应该担心将复制功能添加到每个实例的对象。该函数本身就是一个对象,所以不会真正被复制,也不会被重新编译或者任何东西。它不会浪费内存,除了函数对象引用本身和任何闭包变量。



对原型进行迭代并复制它也不应该让您担心,我想你将不会有gazillion方法。



因此,如果您需要支持 proto 不可设置的环境,您自己的最后解决方案可能是最好的解决方案,而且您并不担心在某些对象已经创建好之后您的原型可能会延长,并且他们可能无法获取更改。

First of all, I don't want to add methods to Function.prototype. Doing that would make them available for all functions and that's not what I'm looking for.

In JavaScript you can create objects with custom prototypes like this:

function CustomObj() {}
CustomObj.prototype = {};
CustomObj.prototype.sayFoo = function () { return 'foo' };

var myCustomObj = new CustomObj(); //=> returns an object: {}
myCusomObj.sayFoo(); //=> 'foo'

You can also create array-like objects with custom prototypes like this:

function CustomArr() {}
CustomArr.prototype = [];
CustomObj.prototype.sayFoo = function () { return 'foo' };

var myCustomArr = new CustomArr(); //=> returns an ordered object: []
myCustomArr.sayFoo(); //=> 'foo'

What I'd like to do is use some kind of constructor to create a function with its own custom prototype in the same way. However, the following does not work:

function CustomFn() {}
CustomFn.prototype = function () {};
CustomFn.prototype.sayFoo = function () { return 'foo' };

var myCustomFn = new CustomFn(); //=> PROBLEM! returns an object: {}
myCustomFn.sayFoo(); //=> 'foo'

// ^^ Here, the prototype was applied but the output was not a function.
myCustomFn(); //=> TypeError: object is not a function

So is there any way to accomplish what I'm trying to do?

UPDATE

Maybe there's another way I could be asking this question that would make it a little clearer.

There's a problem with the idea of a closure:

function makeFn() {
  var output = function () { /* do some stuff */ };
  output.foo = function () { /* do some stuff */ };
  return output;
}
var specialFn = makeFn();

Essentially, this technique gives me what I want. However, the problem is that every time I call makeFn, output.foo has to be created as a totally independent function that takes up its own memory. Gross. So I could move that method out of the closure:

var protoMethods = {
  "foo" : function () { /* do some stuff */ }
};
function makeFn() {
  var output = function () { /* do some stuff */ };
  for (var i in protoMethods) {
    Object.prototype.hasOwnProperty.call(protoMethods, i) &&
      (output[i] = protoMethods[i]);
  }
  return output;
}
var specialFn = makeFn();

But now I have to manually do an iteration every time I call makeFn which would be less efficient than if I could just assign protoMethods to be the prototype of output. So, with this new update, any ideas?

解决方案

It is a tricky thing indeed, more complicated than it should be if the language was designed well...

Basically, you just can't do it cleanly in current versions. Objects other than functions can not be callable.

In future Javascript versions, you can do it with a "proxy" object that can define a "call" handler. But it is still way too complicated and contrived in my opinion.

Another way to go about it is to make your object a real function, not a custom object. Then try to set its __proto__, which is non-standard yet but works in most modern browsers, except Opera and IE 8 or less. Also maybe set its constructor property for faking instanceof checks... such hacks are quite tricky though and results will vary a lot with environments.

The following example works fine on my Firefox: http://jsfiddle.net/Q3422/2/

function MyFun() {
    if (!this || this==window) {
        return new MyFun();
    }

    var f = function() {
        return "thanks for calling!";
    }
    f.__proto__ = MyFun.prototype;
    f.constructor = MyFun;

    return f;
}

MyFun.prototype = {
    foo: function() {
        return "foo:" + this();
    },
    __proto__: Function.prototype
};

var f = new MyFun();
alert("proto method:"+f.foo()); // try our prototype methods
alert("function method:"+f.call()); // try standard function methods
alert("function call:"+f()); // try use as a function
alert('typeof:' + typeof f); // "function", not "object". No way around it in current js versions
alert('is MyFun:' + (f instanceof MyFun)); // true
alert('is Function:' + (f instanceof Function)); // true

Just wanted to add that you should not be worried about "copying" functions to each instance of your objects. The function itself is an object, so is never really copied, nor is it recompiled or anything. It does not waste memory, except for the function object reference itself and any closure variables.

Iterating over the prototype to copy it should not concern you as well, I guess you will not have a gazillion methods.

So your own last solution is probably the best if you need to support environments where proto is not settable, and you are not worried that your prototype might get extended after some objects already got created and they may not pick up the changes.

这篇关于你可以使用JavaScript中的自定义原型创建函数吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆