How Do I Make A Callable Js Object With An Arbitrary Prototype?
Solution 1:
There's nothing to stop you from adding arbitrary properties to a function, eg.
functionbar(o) {
var f = function() { return"Hello World!"; }
o.__proto__ = f.__proto__;
f.__proto__ = o;
return f;
}
var o = { x: 5 };
var foo = bar(o);
assert(foo() === "Hello World!");
delete foo.x;
assert(foo.x === 5);
I believe that should do what you want.
This works by injecting the object o
into the prototype chain, however there are a few things to note:
- I don't know if IE supports
__proto__
, or even has an equivalent, frome some's comments this looks to only work in firefox and safari based browsers (so camino, chrome, etc work as well). o.__proto__ = f.__proto__;
is only really necessary for function prototype functions like function.toString, so you might want to just skip it, especially if you expecto
to have a meaningful prototype.
Solution 2:
I'm looking to make a callable JavaScript object, with an arbitrary prototype chain, but without modifying Function.prototype.
I don't think there's a portable way to do this:
You must either set a function object's [[Prototype]] property or add a [[Call]] property to a regular object. The first one can be done via the non-standard __proto__
property (see olliej's answer), the second one is impossible as far as I know.
The [[Prototype]] can only portably be set during object creation via a constructor function's prototype
property. Unfortunately, as far as I know there's no JavaScript implementation which would allow to temporarily reassign Function.prototype
.
Solution 3:
The closest cross browser thing I have come is this (tested in FF, IE, Crome and Opera):
function create(fun,proto){var f=function(){};
//Copy the object since it is going to be changed.for (var x in proto)
f.prototype[x] = proto[x];
f.prototype.toString = fun;return new f;
}
varfun=function(){return"Hello world";}
var obj={x:5}
var foo=create(fun,obj);
foo.x=8;
alert(foo); //Hello world
alert(foo.x); // 8
delete foo.x;
alert(foo.x); // 5
Solution 4:
You cannot do it in a portable way. However if you think about it, if the purpose of delete foo.x;
is to reset the value of x
, you could provide a reset()
method on foo
that will restore missing properties to their default values.
// Object creation and initialisation
(foo=function()
{
alert("called");
}).reset = function()
{
if(!("x"inthis)) this.x=42;
};
foo.reset();
// Using our callable objectalert(foo.x); // 42foo(); alert(foo.x); // called; 42
foo.x=3; foo.reset(); alert(foo.x); // 3 [*]delete foo.x; foo.reset(); alert(foo.x); // 42
(Tested in Chromium and Internet Explorer, but this should work in all browsers.)
In the line marked with [*]
the call to reset
is really not necessary, but it's there to demonstrate that it doesn't matter if you call it accidentally, and that this generalises to more than one property easily.
Note that in the function body of our callable object this
will refer to the containing scope, which will probably not be that useful to us since we'll want the function body to access the object members. To mitigate this, wrap it in a closure like this:
foo = (function()
{
varself = function()
{
self.x = 42;
};
returnself;
})();
foo(); alert(foo.x); // 42
Post a Comment for "How Do I Make A Callable Js Object With An Arbitrary Prototype?"