Reputation: 67
I need to implement two functions in JavaScript: isConstructor(x)
and constructorName(x)
isConstructor(x)
should return true
in case the argument x
is a constructor function, and false
, otherwise. For example,
isConstructor(Date) === true
isConstructor(Math.cos) === false
constructorName(x)
should return the constructor name for each proper constructor function x
. So e.g.
constructorName(Date) === 'Date'
I can only think of an ugly implementation for both functions, where I create a command
string
"var y = new x()"
which is then called with an eval(command)
in a try/catch
statement. If that eval
call succeeds at all, I call x
a constructor. And I retrieve the name of x
indirectly by asking for the class name of the prototype of y
, something like
var constrName = Object.prototype.toString.call(y).slice(8,-1); // extracts the `ConstrName` from `[object ConstrName]`
return constrName;
But all this is very ugly, of course. How can I do this properly?
Upvotes: 4
Views: 440
Reputation: 67
Thank you all for your very clear and helpful answers! I think I do understand the facts now, but I also got some helpful hints that pointed me to ECMAScript details I didn't know, yet. I need to dive into the literature a little more. Thank you, again! Tom
Upvotes: 0
Reputation: 1289
Like many said in JavaScript almost any function object is a constructor (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function). However if you want to distinguish between the native functions that can't be constructors you can try:
function isConstructor(x) {
return typeof x === 'function' && typeof x.prototype !== 'undefined';
}
Getting the name is definitely trickier, you can use the Function.prototype.toString.apply(x)
and match the name, but for example with the jQuery object that would be an empty string, i.e. if it's anonymous function.
Upvotes: 2
Reputation: 147363
The definition of a constructor is an Object that implements an internal [[Construct]]
method. The only way to test for that is to call it as a constructor and see what happens. You can't test for internal properties other than the [[Class]]
property using Object.prototype.toString
.
Any user defined ECMAScript function is a constructor by default, e.g.
function foo(){}
can be called as a constructor. A function is an object that implements an internal [[Call]]
method and therefore typeof will return "function". But not all functions are constructors, e.g.
typeof document.getElementById // function
but
new document.getElementById()
will throw a type error because it's not a constructor. There are also constructors that aren't functions:
typeof XMLHttpRequest // object
XMLHttpRequest is a constructor, but it doesn't have [[Call]]
so can't be called as a function:
var x = XMLHttpRequest() // TypeError: XMLHttpRequest isn't a function
Lastly, you could try testing for a prototype property that is an object or function, but that also isn't reliable since a prototype property could be added to pretty much any object, host or native.
So the bottom line is that try..catch is probably the only way.
Upvotes: 1
Reputation: 173542
There's only an approximation to this supposed problem; whether a function can be invoked using new
can't be reliably done without actually trying to perform such a call and check for a TypeError:
function isConstructor(fn)
{
try {
var r = new fn(); // attempt instantiation
} catch (e) {
if (e instanceof TypeError) {
return false; // probably shouldn't be called as constructor
}
throw e; // something else went wrong
}
return true; // some constructors may not return an instance of itself
}
The problems with this:
instanceof obj === func
;Upvotes: 1
Reputation: 10528
If you don't mind creating a test instance of the function you could do the following:
function isConstructor(func) {
var t = new func();
return (t instanceof func);
}
BUT: this only workes if the constructor accepts no arguments. It might as well throw an exception. If it does you could try other (not so reliable) things, like checking if the name of the function starts with an uppercase Letter.
Upvotes: 0