-1

I have a function that accepts a callback and bind this to it. I want to throw an error if the function is called with an arrow function as callback (because I cannot bind this to arrow functions).

Something like:

doSomethingWithMyCallback(function(){}); // ok
doSomethingWithMyCallback(() => {}); // should throw an error

How can I check if the callback is not an arrow function (i.e. I can bind this to it)?

Hugo Mota
  • 11,200
  • 9
  • 42
  • 60
  • 1
    `f.toString()`? . – zerkms Oct 11 '16 at 01:05
  • 1
    The entire premise of the question is wrong. You can successfully call an arrow function with a new context, and the arrow function will do the right thing and completely ignore it. That's the entire point, and throwing an error would be foolish. Likewise, you have no way to tell if someone passed `someFunction.bind(this)` as a parameter to `doSomethingWithMyCallback`. – zzzzBov Oct 11 '16 at 01:11
  • Could you pass `this` as a parameter to `function(thisArg){}` or `(thisArg)=>{}` instead of using `.bind()`? – guest271314 Oct 11 '16 at 01:11
  • @zzzzBov I think they bind the proper context to a passed function, and if it is impossible - then the operation makes no sense. Treat it as a monkey patching without mutating objects. – zerkms Oct 11 '16 at 01:13
  • @zzzzBov it's a legitimate question. If I should do it or not is an entirely different discussion. Don't go judging me since you don't even know why I'm asking. – Hugo Mota Oct 11 '16 at 01:36
  • @guest271314 yes I could. It would work just fine. I just want to know if I can keep the signature of the callback pristine (because it will be receiving it's own arguments). – Hugo Mota Oct 11 '16 at 01:36
  • @hugo_leonardo, it seems you don't understand what I'm telling you. It's literally not possible to know if the function passed in is an arrow function. Especially because it is essentially equivalent to `function () {}.bind(this)`. You could attempt to use `toString`, but that's easily defeated by overriding `toString` on any function passed in. Whatever use case you *think* you've come up with for why you want to do this is most likely an [XY Problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – zzzzBov Oct 11 '16 at 01:52
  • @zzzzBov if overriding `toString` is what makes you worry you can call it on prototype. – zerkms Oct 11 '16 at 02:00
  • 2
    See also [Better way to check if function is already bound in plain JavaScript?](http://stackoverflow.com/q/39191045/1048572) - and really, you should never need to do this. – Bergi Oct 11 '16 at 02:09
  • @zzzzBov Given the best answer until now is `toString`, you are right about this not being a good solution to my problem. But I wouldn't know that if I didn't write this question, would I? I really don't think there are "dumb" questions when it comes to learning. – Hugo Mota Oct 11 '16 at 02:37
  • @hugo_leonardo, I don't recall calling the question dumb. My comment was to point out that you're asking a question based on a flawed premise and that you should reevaluate the context. – zzzzBov Oct 11 '16 at 02:47
  • @zzzzBov well...sorry then. I guess I just misunderstood you. The question is a duplicate anyway, so there's no point in arguing about it anymore. My bad :p – Hugo Mota Oct 11 '16 at 03:02

1 Answers1

5

The ES2015 standard makes the definition of Function.prototype.toString more clear (compared to ES5.1) and now it's possible to determine whether it is a "normal" or an arrow function using it.

The string representation must have the syntax of a FunctionDeclaration, FunctionExpression, GeneratorDeclaration, GeneratorExpression, ClassDeclaration, ClassExpression, ArrowFunction, MethodDefinition, or GeneratorMethod depending upon the actual characteristics of the object.

The first character of f.toString() would be 'f' (as in function) if it's a "normal" function or an open parentheses '(' (as in () => {}).

If one is worry about a function overriding the function's toString one may call it with Function.prototype.toString.call(f).

References:

c3r38r170
  • 25
  • 1
  • 10
zerkms
  • 249,484
  • 69
  • 436
  • 539
  • 1
    *"`f.toString()` would come with a first character `f` (as in `function`) if it's a "normal" function or with an open parentheses (..."* FWIW, `(callback => callback.toString())(foo => foo * 2);` returns a string starting with `f` on V8 (Chrome), because V8 doesn't add the parens around a single parameter if you leave them off. You're better off with a more thorough check: https://www.npmjs.com/package/is-arrow-function. But I'm not entirely convinced by that one, either, since it doesn't allow for default parameter values with parens in them. – T.J. Crowder Nov 10 '18 at 14:20
  • @T.J.Crowder oh gosh, in that case I think one needs that it either starts with a parentheses or not "`function` followed by a space followed by an equal character". But indeed even that is not guaranteed by the standard :-S – zerkms Nov 10 '18 at 21:37
  • 1
    Yeah. I think if we really need to know (I have a use case, but there can't be *that* many), it takes firing up a full parser, since a default parameter value can be *anything*, including (say) a function definition filled in arbitrary code of unlimited complexity. Jordan Harband disagrees, though, and he's a smart cookie, so... Now, if there were an accessor for [[ThisMode]] (or [[HomeObject]], since I think methods are the only other function type that don't have a `prototype` property)... I think accessors for [[HomeObject]] would be useful for other reasons, too. – T.J. Crowder Nov 11 '18 at 08:47