4

How can I differentiate between these three things in ES6 using its reference?

let x = i => i+1;

class y { constructor(i) { this._i=i+1; } get i(){ return this._i;} }

function z(i) { return i+1; }

Example:

test(x) //=> 'arrow'
test(y) //=> 'class'
test(z) //=> 'function'

And how can I differentiate between these things in transpilers - Traceur / Babel?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Boopathi Rajaa
  • 4,659
  • 2
  • 31
  • 53
  • 1
    What is your usecase? I would try to call func.toString() and see what i'm getting back and maybe analyse it. – Bnaya Aug 11 '15 at 08:35
  • I'd strongly suggest that class names follow the long-standing tradition of constructors having uppercase first letter. That way it's easy to tell at a glance that `Function()` is either a class or constructor and `function()` is a function. – slebetman Aug 11 '15 at 17:01

2 Answers2

7

How can I differentiate between these things in ES6?

  • arrow functions are functions that cannot be used as constructors, and don't have a .prototype property. However, methods don't either. They inherit from Function.prototype.
  • classes are functions that can't be called without new, and that have a .prototype object which is normally not empty. If the extends keyword was used, they don't inherit from Function.prototype.
  • functions are functions that can be called either way, and do have a .prototype that is normally empty. They inherit from Function.prototype.
  • generator functions are functions that do have a .prototype which inherits from the intrinsic GeneratorPrototype object, and they inherit from the intrinsic Generator object.

As you can see, there are some clues. However, the properties and inheritance can always be messed with, so you cannot really trust it. Whether a function is a constructor (can be called with new) cannot be determined from outside, you have to call it and see whether it throws - which could be faked as well.

So your best bet might be Function.prototype.toString, to see how the source looked like. If your ES implementation supports that.

And how can I differentiate between these things in transpilers?

I don't think any transpiler implements prototype-less arrows and methods. Whether a class constructor throws upon being called depends on the looseness of the transpilation, but that's not a good way for distinction anyway.
toString doesn't work either afaik.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    Thanks!. I just tried it out on v8 and it works just fine. https://gist.github.com/boopathi/7c4adc4f4790f432838d . It fails when I try it on methods though. – Boopathi Rajaa Aug 14 '15 at 13:46
  • 1
    Updated the gist. Now supports detecting generators and methods too. I hope my assumptions are correct. Mentioned them in code comments. – Boopathi Rajaa Aug 14 '15 at 15:41
1

You can't the first two cases get transpiled into this:

var x = function x(i) {
  return i + 1;
};

function z(i) {
  return i + 1;
}

For the last one you could check if it complains if it's a class when you call it:

function isClass(instance){
  try{
    instance()
  }catch(e){
    return e.message === "Cannot call a class as a function";
  }
  return false;
}

But that will obviously trigger the side effects of calling it, so it doesn't work in the general case.

Kit Sunde
  • 35,972
  • 25
  • 125
  • 179