1

I have a js object that could be a function or a class, ie. it is equal to one of:

class {
  constructor( param ) {  }
  onCreate() { } 
};

Or,

function ( param ) { };

Turns out they have more in common then I expected (eg. both have a constructor). Please tell me the simplest way to determine which of these types my js object refers to.

The solution must work in node 4.3.2.

edit: To clarify, the object that I'm trying to differentiate is a class or a function, not an instance of these. And yes, I'm aware that a class is just syntatic sugar, that's what is making this difficult.

Tom
  • 17,103
  • 8
  • 67
  • 75
  • Thanks for asking this. I have had the same problem to differentiate them because I could declare them either way and use them as class. Hopefully we'll get this sorted out. – Running Buffalo Dec 15 '16 at 23:16
  • 2
    It's not entirely clear what you're asking since your examples are not valid javascript. The key thing is that ES6 classes are just syntactic sugar, not a new type. Maybe it would help if you could add something outlining why you need to make this distinction. – pvg Dec 15 '16 at 23:22
  • 1
    What is the real problem you're trying to solve? An ES6 class isn't really distinct from a function, it is another syntax to define a constructor function and set its .prototype property. – PMV Dec 15 '16 at 23:58
  • complete JS would definitely help. I assume that you have an object and you need to determine if it's been initialized via class or function. In that case, use `__proto__` as showcased in my answer below – manonthemat Dec 16 '16 at 00:03

4 Answers4

2

A class is not a "real thing" in the JavaScript specification beyond being syntactic sugar for the composition of pre-existing language primitives.

Vendors may make distinction possible (e.g. the toString method suggested in another answer), but I have scanned the spec and I don't think that is part of it... so is vendor-defined and therefore cannot be relied upon.

Indeed: Firefox 50 on the Mac does not print the word "class" (it uses the word "function") when toString is used on a class.

I don't know much about JS classes, so I could be wrong...

Ben Aston
  • 53,718
  • 65
  • 205
  • 331
1

I get this in the REPL with v6.9.2:

λ node -i
> class A {}
[Function: A]
> let B = function() {}
undefined
> A.toString()
'class A {}'
> B.toString()
'function () {}'

There may be another more reliable way, but checking for class should work:

if (A.toString().match(/^class/)) {
  // it's a class
}
elclanrs
  • 92,861
  • 21
  • 134
  • 171
  • Yes, I tried this and it worked for me, thanks. Kinda' ugly, but I guess that's how it goes. – Tom Dec 16 '16 at 00:15
  • 1
    Well, it will work, on one particular implementation, unless someone decided to override `.toString`, either on the individual object level or on a higher level e.g. `Function.prototype.toString` – PMV Dec 16 '16 at 00:18
0

The answer to these sorts of questions is almost always Lodash (or Underscore). Lodash has isFunction:

Checks if value is classified as a Function object.

There are a TON of things in Lodash that people try to re-create all the time. Lodash is almost certainly doing it the right way and it's well-maintained.

Moral of the story: check if Lodash does X before you write a function to do X.

coffee> ld.isFunction
[Function: isFunction]
coffee> ld.isFunction(Date)
true
coffee> a = b:2
{ b: 2 }
coffee> ld.isFunction(a) 
false
coffee> 
coffee> d = new Date()
2016-12-17T00:02:58.950Z
coffee> ld.isFunction(d) 
false
jcollum
  • 43,623
  • 55
  • 191
  • 321
  • Are you sure? I just tried it and for me that function returns true in both cases (a function object vs a class object). – Tom Dec 16 '16 at 21:26
  • Are you talking about a constructor for a class? – jcollum Dec 16 '16 at 23:52
  • As in my question above, an ES6 class object: var c = class C { }; isFunction returns true for an ES6 class object. – Tom Dec 17 '16 at 01:12
  • I think you're asking a question that doesn't have an answer. This may help http://stackoverflow.com/questions/1249531/how-to-get-a-javascript-objects-class – jcollum Dec 19 '16 at 15:56
  • No, that's not it (the SO link you provided). The Q does have an answer - the one I accepted. – Tom Dec 19 '16 at 16:03
  • I sure wouldn't use that in production code. If it does the job and it's not production, heck, why not. – jcollum Dec 19 '16 at 20:48
0

I thought it worth adding that, if one knows the names of the class or function, you can distinguish them like this.

> const C = class CC { };
undefined
> const F = function FF() { };
undefined
> C.prototype
CC {}
> F.prototype
FF {}

And if they are anonymous (not sure if that terminology is used in js) then you get just '{}'.

In a program you can use util.inspect (the name part dissapears with toString) to get at these strings.

Tom
  • 17,103
  • 8
  • 67
  • 75