1

Update here is the final and working code -- just in case if somebody found it helpful: jsfiddle

I've written this as the type detector. It works very well in all cases -- so far whatever I've tested, but fails only in one case.

First, here is the snippet: jsfiddle

var TypeOf = function ( thing ) {
    var typeOfThing = typeof thing;
    if ( typeOfThing === 'object' ) {
        typeOfThing = Object.prototype.toString.call(thing);
        if ( typeOfThing === '[object Object]') {
            if ( thing.constructor.name ) 
                typeOfThing = thing.constructor.name;
            else if ( thing.constructor.toString().charAt(0) === '[' ) 
                typeOfThing = typeOfThing.substring(8,typeOfThing.length - 1);
            else
                typeOfThing = thing.constructor.toString().match(/function\s*(\w+)/)[1];
        } else {
            typeOfThing = typeOfThing.substring(8,typeOfThing.length - 1);
        }
        return typeOfThing.toLowerCase();
    } else {
        return typeOfThing;
    }
}

The problem is that if I define the function at parse-time then it will work perfectly fine:

function me () {};
var you = new me();
console.log('Type of you: ' + TypeOf(you));    // me

However if I just define it at run-time, then it won't work:

var me = function () {};
var you = new me();
console.log('Type of you: ' + TypeOf(you));    // nope

As far as I can see in the parse-time case the constructor is something like function me () {}, so I can get it with /function\s*(\w+)/, however in the run-time case the constructor is function () {}.

Is there any way to get this to work? And also, are there any other cases that this snippet might potentially fail to detect the type?

Update as @lonesomeday mentioned in the comments, it seems that I'm trying to get the name of an anonymous function. That looks a little bit scary to me. Is that even possible?

Update as @jackson said below, it seems that the correct output should be function not me. Is that really correct?

Community
  • 1
  • 1
Mahdi
  • 9,247
  • 9
  • 53
  • 74
  • 2
    You are essentially asking how to get the name of an anonymous function. That is, by definition, rather hard to do. – lonesomeday Dec 07 '13 at 11:02
  • @lonesomeday Thanks, you're right, I will try to rephrase the question title as well. – Mahdi Dec 07 '13 at 11:03
  • Note also that you could do `thing.constructor.name` in browsers that support it (!IE, basically). By the way, when I say "rather hard to do" above, I actually mean "by definition impossible". – lonesomeday Dec 07 '13 at 11:06
  • @lonesomeday I actually have it up there in the code, but that didn't work also ... Do you mean I should implement it in another way? – Mahdi Dec 07 '13 at 11:08
  • Just my $0.02: I really think you're trying to solve the wrong problem. It's one thing to make a compiler check all the types (and that's what TypeScript is about). It's another thing to check all the types in run-time - it's very... weird, to say the least. – raina77ow Dec 07 '13 at 11:25
  • @raina77ow You mean it's useless or what? But thanks anyways, Javascript still confuses me couple of times a day, so I know that I might do weird things. – Mahdi Dec 07 '13 at 11:32

3 Answers3

2

Your test actually succeeded. The type of that variable is indeed "function".

Given the juxtaposition of your function me () {}; in your tests, you seem to have expected that the nearby test with slightly-modified syntax would have a similar result. But this is not the case. There is no reason why you would have the "class" (not actually a class) of "me". It is just a regular old "function", nothing more.

Jackson
  • 9,188
  • 6
  • 52
  • 77
  • Hah! Is that really correct? ... Let me add it to the original question! but good point, thanks! – Mahdi Dec 07 '13 at 11:17
  • Yes. Thinking in terms of C, you could consider `me` a "pointer" to a regular function. In JavaScript, you just happen to be able to invoke any referenced function by appending parens to end of the variable that references it. – Jackson Dec 07 '13 at 11:23
1

The type of that variable's constructor is a function, not me. Your second example uses an anonymous function that happens to be referenced by a variable called me.

Think about what would happen if you reassigned me to a different object:

var me = function () {};
var you = new me();
me = 10;
//what if TypeOf(you) had returned me? that would be confusing, because me is now an integer

If you do care about the name of a variable that stored an anonymous function (which is a fragile thing to do for the aforementioned reason), you could use this workaround.

It find the name of the global variable that currently holds a reference to an object's constructor:

function checkForAnAnonymousConstructor(o) {
    for(var f in window) {
        if(window[f] == o.constructor) return f;    
    }
}

me = function() { }
var you = new me();
console.log(checkForAnAnonymousConstructor(you)); //-> me

//This only works whilst the reference is current
me = 10
console.log(checkForAnAnonymousConstructor(you));// -> undefined

http://jsfiddle.net/nE9eP/2

joews
  • 29,767
  • 10
  • 79
  • 91
  • Nice, thanks for the effort. I will wait a bit more to see if I get more answers! Jackson actually had a good point tho ... – Mahdi Dec 07 '13 at 11:28
  • Yes, his is the right answer to "what is the type of this variable" - this is subtly different, but it match what you originally expected. – joews Dec 07 '13 at 11:31
  • 1
    This guy -> http://stackoverflow.com/a/338053/1468130 actually prefers the `var x = function() {};` approach because it lets him control visibility. To each his own. The "validity" of that approach kind of depends on the architecture of your application. Given the outcome of toString() I am led to believe that that is not how the language is designed or should be approached, though the typeof operator is so lousy that it's difficult for me to be confident in my opinion. (Seems like they didn't really care about types when they designed JS, so to a certain extent that leaves it up to us.) – Jackson Dec 07 '13 at 11:42
  • @joews Hey! Even tho if you actually answered what I was asking for, but I still think that Jackson's answer is more correct, so I just went for that. Thanks again for your time and explanation. :) – Mahdi Dec 07 '13 at 12:40
0

you have to consider a very important point regarding JavaScript functions, which is the way you define them. when you do var me = function () {} you have actually created a anonymous function, a function without any name and then assigned it to a variable. when you create a function like this:

function myfunc(){}

it is actually like:

var myfunc = function myfunc(){};

the most important point here is, function's name is not unique, you can create several functions with the same name.

var Func1 = function myfuncname(){ this.name = 'Func1'; };

or

var Func2 = function myfuncname(){ this.name = 'Func2'; };

as you see here we have 2 different function which if you use your TypeOf function the result is the same:

TypeOf(new Func1) -> myfuncname

and also

TypeOf(new Func2) -> myfuncname

BTW, your TypeOf function is perfectly correct but the only problem here is, if you want to get the correct result you have to change:

var me = function () {};
var you = new me();
console.log('Type of you: ' + TypeOf(you));

to:

var me = function me() {};
var you = new me();
console.log('Type of you: ' + TypeOf(you));

I have gone thru this arduous task before and I would be happy to share anything you need.

Mehran Hatami
  • 12,723
  • 6
  • 28
  • 35
  • Well, you're somehow right, but first you shouldn't give a name to anonymous functions I guess -- like `mufuncname()`, it's redundant and probably confusing, and even if you want to do that then you should not come up with a same name for two different functions. But thanks anyways for the heads-up :) – Mahdi Dec 07 '13 at 12:08
  • For me, the result of `TypeOf(Func1)` and `TypeOf(Func2)` was "function" for each. http://jsfiddle.net/9fsqy/1/. – Jackson Dec 07 '13 at 12:27
  • Also, the names of functions, in named function expressions, are only available within the scope of said functions. See the third block of code on this answer: http://stackoverflow.com/a/338053/1468130 – Jackson Dec 07 '13 at 12:30
  • Sorry about the mistake, what I meant is `TypeOf(new Func1)` and `TypeOf(new Func2)` would be the same – Mehran Hatami Dec 07 '13 at 13:56
  • I did the same task to be used in my JavaScript team codes but my `TypeOf` function was to use only for objects of our JavaScript class types. I had asked all team members to use appropriate names for our JavaScript classes(Functions). My main point is if your functions have no name or the names are duplicated your `TypeOf` function would not be able to return a appropriate result. – Mehran Hatami Dec 07 '13 at 14:10