Reputation: 11445
I'd like to call a function without knowing how it should be called/instantiated. For my understanding there are two ways we can either use new Foo()
or Foo()
.
As I need a wrapper to call this function, let's say it's basically a proxy. I have a reference to a function but don't know in which way I should call it, wether it is meant to be a constructor or a plain javascript function.
As it seems that there is no way to distuingish between both ways I came up with the following.
var delegate;
var Foo = function() { };
Foo.prototype.foo = function() { alert("foo") };
var bar = function(value) { alert(value); }
function construct(constructor, args) {
function F() {
return constructor.apply(this, args);
}
F.prototype = constructor.prototype;
return new F();
}
var proxy = function() { return construct(delegate, arguments) };
delegate = bar;
proxy("bar");
delegate = Foo;
new proxy().foo();
This gives me the expected result and seems to work. Do you see anything bad with this solution? Is it bad to call a regular function with new
? What are the downside of this technique?
The code is based on the following question "Use of apply with the new operator"
Upvotes: 4
Views: 131
Reputation: 665554
Is it possible to distinguish between a constructor and a normal function?
No. Every normal (user-defined) javascript function can act as both. From inside the function, you might do some reasoning depending on how the this
value looks like, but this is not reliable.
See also How to detect if a function is called as constructor?
I have a reference to a function but don't know in which way I should call it, wether it is meant to be a constructor or a plain javascript function.
However, you don't need to know that - proxy
itself is called as either as a constructor or plain function by someone who knows it.
Do you see anything bad with my solution?
That closure over delegate
which is later changed is ugly when left in the open. In your case you don't really seem to need it, a plain proxy = bar;
and proxy = Foo;
would be sufficient there. Also, your construct
function looks unnecessary.
Is it bad to call a regular function with new? What are the downside of this technique?
If the function does not use this
, then no problems will arise, but there's overhead in constructing the instance object.
For a proxy function that is passed somewhere else (so that we cannot easily change the reference), I'd use an explicit setter for delegate
:
function makeProxy(delegate) {
function proxy() {
return delegate.apply(this, constructor);
}
proxy.prototype = delegate.prototype;
return {
proxy: proxy,
setTarget: function(d) {
delegate = d;
proxy.prototype = d.prototype;
}
};
}
var p = makeProxy(bar);
p.proxy("bar");
p.setTarget(Foo);
new (p.proxy)().foo();
Upvotes: 2