An object's constructor name as a string. Can definitely be determined?

P

Peter Michaux

Hi,

I want to know the name of an object's constructor function as a
string. Something like this

<script type="text/javascript">
function Foo(){};
var a = new Foo();
alert('"' +
a.constructor.toString().match(/function\s*([a-zA-Z\$][\w\$]+)[^\w\$]/)[1]
+ '"');
</script>

Although this works in IE, Opera, Firefox, Safari I'm not sure that it
is guaranteed to work.

I looked in the ECMA-262 specs about the returned string for
Function.prototype.toString() in section 15.2.4.2. It says that the
whitespace, line terminators and semi-colon use are implementation
dependent. I think the above regular expression can handle those
difference.

What I'm worried about is that he specs say the return value has the
form of a "function declaration". Does that mean the returned string
will definitely contain the name of the constructor function? Could it
instead return something like just "function () {}"?

Thank you,
Peter
 
R

RobG

Peter said:
Hi,

I want to know the name of an object's constructor function as a
string. Something like this

<script type="text/javascript">
function Foo(){};
var a = new Foo();
alert('"' +
a.constructor.toString().match(/function\s*([a-zA-Z\$][\w\$]+)[^\w\$]/)[1]
+ '"');
</script> [...]
What I'm worried about is that he specs say the return value has the
form of a "function declaration". Does that mean the returned string
will definitely contain the name of the constructor function? Could it
instead return something like just "function () {}"?

A quick test shows that you can use an anonymous function as a
constructor, and it is returned in the form of a function declaration,
but it's actually a statement:

var nameObj = function(name){
this.name = name;
this.showName = function(){alert(this.name);}
}

var x = new nameObj('Peter');
x.showName();
alert(x.constructor);

shows:

function (name) { ...}

which only makes sense as a function statement. I guess you could say
it's in the form of a declaration because the left hand side is
missing. Of course you might fix that with:

var nameObj = function nameObj (name){ ... }

But that may not be helpful. In some browsers the constructor object
has a name property, but not all unfortunately. Can I be of any less
help? :)
 
D

Douglas Crockford

Peter said:
Hi,

I want to know the name of an object's constructor function as a
string. Something like this

<script type="text/javascript">
function Foo(){};
var a = new Foo();
alert('"' +
a.constructor.toString().match(/function\s*([a-zA-Z\$][\w\$]+)[^\w\$]/)[1]
+ '"');
</script>

Although this works in IE, Opera, Firefox, Safari I'm not sure that it
is guaranteed to work.

No, it's not. I don't like object models where it is necessary to query
instances about their types. But if you feel you must, make it reliable. The
constructor property is not reliable because it is lost in the simple
inheritance pattern:

function Bar(){}
Bar.prototype = new Foo();

var b = new Bar();
alert(b.constructor === Bar); // produces false

So be explicit in identifying your type names.

Foo.prototype.type = 'Foo';
Bar.prototype.type = 'Bar';

alert(a.type);
alert(b.type);

http://javascript.crockford.com/
 
P

Peter Michaux

RobG said:
Peter said:
Hi,

I want to know the name of an object's constructor function as a
string. Something like this

<script type="text/javascript">
function Foo(){};
var a = new Foo();
alert('"' +
a.constructor.toString().match(/function\s*([a-zA-Z\$][\w\$]+)[^\w\$]/)[1]
+ '"');
</script> [...]
What I'm worried about is that he specs say the return value has the
form of a "function declaration". Does that mean the returned string
will definitely contain the name of the constructor function? Could it
instead return something like just "function () {}"?

A quick test shows that you can use an anonymous function as a
constructor, and it is returned in the form of a function declaration,
but it's actually a statement:

var nameObj = function(name){
this.name = name;
this.showName = function(){alert(this.name);}
}

var x = new nameObj('Peter');
x.showName();
alert(x.constructor);

shows:

function (name) { ...}

which only makes sense as a function statement. I guess you could say
it's in the form of a declaration because the left hand side is
missing. Of course you might fix that with:

var nameObj = function nameObj (name){ ... }

But that may not be helpful. In some browsers the constructor object
has a name property, but not all unfortunately. Can I be of any less
help? :)

Hi Rob,

I tested the things you mentioned also. It seems the the return value
of toString() can take the form of a function statement when the
function is anonymous. So does this mean the ECMA specs are a little
bit wrong? If a function is anonymous, there is no way that toString
will be able to return a function declaration since the identifier is
not available.

Thanks,
Peter
 
V

VK

Peter said:
It seems the the return value
of toString() can take the form of a function statement when the
function is anonymous. So does this mean the ECMA specs are a little
bit wrong? If a function is anonymous, there is no way that toString
will be able to return a function declaration since the identifier is
not available.

That was already explained at
<http://groups.google.com/group/comp.lang.javascript/msg/81452faadf0019d1>
- please read it carefully.

This way it shouldn't surprise you any more than
function foo() {}
var bar = foo;
alert(bar.toString()) // that the name will be? foo of course

ECMAScript specs are not exactly wrong, but they are very confusingly
written: so confusingly actually that professional C++ programmers did
not get it right in application to this matter and they had to say
sorry latter (JScript team) though sorry should be ECMA's free-lancers.

In application to your routine two more issues has to be taken into
consideration:

1) var foo = function(){} creates anonymous function with toString
method returning "function(){..."
At the same time anonymous functions in event handlers (like one in
<body onload="") has toString method returning "function anonymous()
{...". The same is for function created by using Function()
constructor. It has nothing to do with some pragrammatical differences,
it was just preserved this way for legacy reasons. Brendan Eich once
had to explain it and say sorry on bugzilla.mozilla.org, later I'll
find the link again.
In any case you have to adjust the neuristic for both possible values
for anonymous functions.

2) toString method can be overloaded to prevent source code dump or to
be used for something completely else. It is rather easy fixable as
well but in such case it looks more like a reverse engineering so I
will not advise: but only point onto such possibility.
 
R

RobG

Peter said:
RobG said:
Peter Michaux wrote: [...]
What I'm worried about is that he specs say the return value has the
form of a "function declaration". Does that mean the returned string
will definitely contain the name of the constructor function? Could it
instead return something like just "function () {}"?

A quick test shows that you can use an anonymous function as a
constructor, and it is returned in the form of a function declaration,
but it's actually a statement:
[...]
I tested the things you mentioned also. It seems the the return value
of toString() can take the form of a function statement when the
function is anonymous. So does this mean the ECMA specs are a little
bit wrong? If a function is anonymous, there is no way that toString
will be able to return a function declaration since the identifier is
not available.

I don't think the specification is wrong or contradictory, the wording
is:

"15.3.4.2 Function.prototype.toString ( )
"An implementation-dependent representation of the function is
returned. This representation has the syntax of a
FunctionDeclaration. Note in particular that the use and placement
of white space, line terminators, and semicolons within the
representation string is implementation-dependent."

The important part is "has the syntax of", it doesn't say "it is" a
function declaration. It is similar to the confusion caused by the
occasional use of "undefined" when "not defined" is meant.

The function is returned in a format that looks like a function
declaration, but since it's anonymous, there is no identifier or name.
The only solution to me is to put an identifier into function
statements, but that will only suit code you can control, not a general
case.

This may be an interesting exercise but using the constructor property
as the basis for program logic is unlikely to be reliable. Try
Douglas' suggestion: give your native function objects an explicit type
parameter.
 
M

Michael Winter

Peter said:
It seems the the return value of toString() can take the form of a
function statement when the function is anonymous. ...

That is precisely the form it /should/ take.
If a function is anonymous, there is no way that toString will be
able to return a function declaration since the identifier is not
available.

You seem to be overlooking the rather important initial sentence:

An implementation-dependent representation of the function is
returned.

An implementation is free to use whatever identifier it likes. An
obvious choice is "anonymous", though anything (including a
randomly-generated identifier) will do.

Mike
 
P

Peter Michaux

RobG wrote:
I don't think the specification is wrong or contradictory, the wording
is:

"15.3.4.2 Function.prototype.toString ( )
"An implementation-dependent representation of the function is
returned. This representation has the syntax of a
FunctionDeclaration. Note in particular that the use and placement
of white space, line terminators, and semicolons within the
representation string is implementation-dependent."

The important part is "has the syntax of", it doesn't say "it is" a
function declaration. It is similar to the confusion caused by the
occasional use of "undefined" when "not defined" is meant.

The function is returned in a format that looks like a function
declaration, but since it's anonymous, there is no identifier or name.
The only solution to me is to put an identifier into function
statements, but that will only suit code you can control, not a general
case.


At the beginning of section 13 of the specs it says

Syntax

FunctionDeclaration:
function Identifier (FormalParameterList_opt) { FunctionBody }

FunctionExpression:
function Identifier_opt (FormalParameterList_opt) {FunctionBody}

Does the following sound reasonable? In the FunctionDeclaration the
Identifier is not optional so a function declaration cannot be
anonymous. An anonymous function is always introduced through a
FunctionExpresssion.

Perhaps the section about toString() for a function should say that the
returned value has the syntax of a FunctionExpression. This would
account for anonymous functions.

This may be an interesting exercise

I think that is all it has become now.

but using the constructor property
as the basis for program logic is unlikely to be reliable.
Try Douglas' suggestion: give your native function objects an explicit type
parameter.

I think this is good advice.

Thanks Rob and Douglas.

Peter
 
V

VK

FunctionDeclaration:
function Identifier (FormalParameterList_opt) { FunctionBody }

FunctionExpression:
function Identifier_opt (FormalParameterList_opt) {FunctionBody}

Does the following sound reasonable? In the FunctionDeclaration the
Identifier is not optional so a function declaration cannot be
anonymous. An anonymous function is always introduced through a
FunctionExpresssion.

Did you try?
<script type="text/javascript">
function() {}
</script>

That is a perfectly valid syntax: but useless program-wise.
FunctionDeclaration is not evaluated, so there is no "hook" left to use
this function in your program. This is all what they tried (but failed)
to say.
Perhaps the section about toString() for a function should say that the
returned value has the syntax of a FunctionExpression. This would
account for anonymous functions.

They couldn't say it in 1999, because already there was a great amount
of scripts using toString value from anonymous functions defined for
intrinsic handlers (see again my other post in this thread). I do agree
in advance that the chosen form for them:
"function anonymous() {..." is sub-optimal and semi-contadictory (if
function is called "anonymous" then it is called somehow and so it is
not anonymous). More logical would be do not use the word "anonymous"
at all as in the latter practice or at least use another order:
"anonymous function(){..."

But whatever was done - it was done, and we have to deal now with the
legacy outcomes.
 
R

Richard Cornford

VK wrote:
Did you try?
<script type="text/javascript">
function() {}
</script>

That is a perfectly valid syntax:

No it is not. No ExpressionStatement may commence with the 'function'
keyword and the Identifier in a Function Declaration is not optional.
but useless program-wise. FunctionDeclaration is not evaluated,
so there is no "hook" left to use this function in your program.
This is all what they tried (but failed) to say.
<snip>

Who are these "they" and why are they trying to be so incoherent?

Richard.
 
D

Douglas Crockford

VK said:
Did you try?
<script type="text/javascript">
function() {}
</script>

That is a perfectly valid syntax: but useless program-wise.
FunctionDeclaration is not evaluated, so there is no "hook" left to use
this function in your program. This is all what they tried (but failed)
to say.

JSLint reports:

Missing name in function statement.

http://www.JSLint.com/
 
V

VK

JSLint reports:

Missing name in function statement.

http://www.JSLint.com/

JSLint is not the script engine, so it's allowed to have different
opinions on different topics ;-)

But I have to reconsider my previous statement:
<script type="text/javascript">
function() {}
</script>
is not a FunctionDeclaration: it is still FunctionExpression. Here we
have "expression without assignment" wich is totally valid byt rather
useless. Functionally it is the same as
<script type="text/javascript">
4;
</script>
or
<script type="text/javascript">
"foobar";
</script>
 
R

Richard Cornford

VK said:
JSLint is not the script engine, so it's allowed to have different
opinions on different topics ;-)

But I have to reconsider my previous statement:

It was a false statement.
<script type="text/javascript">
function() {}
</script>
is not a FunctionDeclaration:

Could not be a FunctionDeclaration because it has no Identifier and the
Identifier is not optional in a FunctionDeclaration.
it is still FunctionExpression.

Being a function expression does not make it "perfectly valid syntax".
Expressions are not the units of a javascript program; they are
FunctionDeclarations and Statements. We have ruled out
FunctionDeclarations and the only form of statements that can be
constructed from a single Expression are ExpressionStatements, where an
Expression statement is _explicitly_ forbidden from commencing with the
- function - keyword. Thus an ExpressionStatement consisting of only a
Function Expression is not "perfectly valid syntax".

I told you this yesterday, but instead of verifying that I was correct
here you are trying to defend another of your false statements. If you
don't know what constitutes syntactically correct javascript (and you
have made it completely clear over the years that you don't, and are
not capable of learning it) it would be better to keep quiet on the
subject.
Here we have "expression without assignment" wich is totally valid

It is a syntax error. It was a syntax error yesterday and will still be
a syntax error tomorrow.
byt rather useless. Functionally it is the same as
<script type="text/javascript">
4;
</script>
or
<script type="text/javascript">
"foobar";
</script>

Except that neither of those are syntax errors, and so may appear in
javascript source code without risking it not being interpretable.

Richard.
 
V

VK

Richard said:
It is a syntax error. It was a syntax error yesterday and will still be
a syntax error tomorrow.


Except that neither of those are syntax errors, and so may appear in
javascript source code without risking it not being interpretable.

Any ECMAScript-compliant engine erroring out on the below, please.

<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8">
<script type="text/javascript">
try {
eval(function(){});
}
catch(e) {
window.alert(e.message);
}

</script>
</head>

<body>

</body>
</html>
 
R

Richard Cornford

Any ECMAScript-compliant engine erroring out on the below, please.

You are a halfwit. In what sense does the code below relate to anything
that has come before?
<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8">
<script type="text/javascript">
try {
eval(function(){});
<snip>

A FunctionExpression is a completely valid argument to a function call,
and the - eval - function does not do anything with non-string
arguments but return them. There is no syntax error here, and so its
not erorring is unsurprising.

It is telling of your actual understanding of this subject that you
make false statements and then when you are corrected start posting
code that you are incapable of seeing as having no relevance to the
question in hand. I suppose here we are suffering again form you not
actually knowing what the code you write is supposed to do, and so
thinking this to relevant when it is not.

Richard.
 
V

VK

Richard said:
It is a syntax error. It was a syntax error yesterday and will still be
a syntax error tomorrow.


Except that neither of those are syntax errors, and so may appear in
javascript source code without risking it not being interpretable.

Any ECMAScript-compliant engine erroring out on the below, please.

<html>
<head>
<title>Untitled Document</title>
<script type="text/javascript">
function(){}
</script>
</head>
<body>
</body>
</html>

P.S. eval in the previous sample was used to wrap possible syntax
errors so make them catchable at run-time. It is useless in this case
(because there are no syntax errors to expect), just an automated
doing: "error", "syntax" keywords triggered the corresponding style in
my head :)
 
R

Richard Cornford

Any ECMAScript-compliant engine erroring out on the below, please.

You mean like Opera 9 reporting a syntax error?
<html>
<head>
<title>Untitled Document</title>
<script type="text/javascript">
function(){}
</script>
</head>
<body>
</body>
</html>

P.S. eval in the previous sample was used to wrap possible syntax
errors

Whatever you may have thought you were using it for the - eval -
function only executes code if its argument is a string, so passing it
a function object guaranteed that it did nothing.
so make them catchable at run-time.

And that is what would have happened, if the argument had been a
string.
It is useless in this case
(because there are no syntax errors to expect),

Not true, If the argument had been the string "function(){};" then the
syntax error would have happened. But achieving that pre-supposes some
sort of knowledge of how javascript works, so you just posted nonsense
instead.
just an automated doing: "error", "syntax" keywords triggered the
corresponding style in my head :)

Gibberish.

Richard.
 
V

VK

Richard said:
You mean like Opera 9 reporting a syntax error?

Yep... Opera 9 errors out. That proves again the old "Web axiom" that
for any feature will be at least one UA that will get it wrong.

Lucky this "feature" has only theoretical interest.
 
R

Richard Cornford

VK said:
Richard Cornford wrote:

Yep... Opera 9 errors out. That proves again the old "Web axiom" that
for any feature will be at least one UA that will get it wrong.

In what sense is reporting a syntax error when code contains a syntax
error getting it wrong? It might be better argued that browsers
tolerating what should be syntax errors are 'getting it wrong', though
browsers being tolerant in the face of incompetent web developers is
hardly a new phenomenon.

Your "web axiom" is typically worthless. A much more useful, and
applicable axiom is; "be liberal in what you accept and strict in what
you send". with being liberal in what they accept being what some
browsers do in tolerating a syntax errors in javascript source code,
and being strict in what you send meaning that you write syntactically
correct code to be sent to the browser in the first place. After all,
has anyone observed any browser ever having a problem with receiving
syntactically correct javascript source code?
Lucky this "feature" has only theoretical interest.

Maybe only "theoretical interest" for you, as you will never know
enough to distinguish between correct syntax and incorrect. But while
you treat browsers that do not understand the 'code' you write as not
being supportable others write code that works fine with them (even
genuinely cross-browser). Could it be that the browsers you deprecate
so much are actually just not tolerating the code you are sending them
because not knowing what is syntactically correct in javascript you are
sending them syntax errors that you cannot recognise. Wouldn't that
leave knowing syntactic correctness having a very practical impact on
the ability to surpass your 'skills' and so write genuinely
cross-browser code?

Richard.
 
V

VK

Richard said:
"be liberal in what you accept and strict in what
you send".

Exactly: and this rule (which is especially true for javascript
engines) is violated on Opera 9. The rule is that a javascript program
may error out only if no available interpretations left: this is why
even utterly wrong scripts are "working" sometimes - but often not in
the intended way.

The exact parsing algorithm was given by you in this thread, as well
as two possible branches of this algorithm.

<script type="text/javascript">
function(){}
</script>

1) Found "function" keyword left hand side, searching for identifier.
2) If an identifier found then this is FunctionDeclaration; if not then
go to step 3
3) No identifier found, left hand side anonymous function. If Opera 9
then go to step 4, otherwise go to step 5
4) Opera 9: "booh, booh... bad syntax... :-("
4) Others: function expression w/o assignment, seems useless but not
our damn business.

This way Opera 9 between i)trying to further interpret the code and ii)
error out is choosing to error out, which is not OK for a reliable
script engine.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top