1

Is typeof foo === 'function' the only way (other than attempting to call the object) to determine whether an object is callable?

If so, is this because it is otherwise impossible to distinguish between a callable object and an object that merely inherits from Function.prototype?

I note that until ES2015, the only way (other than supplying a string to Function, and possibly eval) to create a callable object, was to use the function () {} syntax, to create a function-object directly; and that ES2015 introduced a way of extending exotic objects like Function, enabling callable objects to be configured using the class CallableClass extends Function syntax, and instantiated using the new CallableClass syntax.

To restate: For all objects, typeof returns 'object' EXCEPT for callable function-objects, for which it returns 'function'. Is this the singular language feature, deliberately included, to enable userland identification of callable objects (because there was no other way)?

Ben Aston
  • 53,718
  • 65
  • 205
  • 331
  • 4
    I'm not sure I'm seeing the reason behind the question. Does `typeof` not work in some cases? Is there a reason you'd need *another* way? – deceze May 20 '22 at 14:50
  • 1
    Prior to 2015 there was also the `Function` constructor (not that it was a great idea to use it). – Pointy May 20 '22 at 14:53
  • 1
    `typeof new CallableClass` will still be `function` . You could look at how other's have addressed it ie. the [is-callable](https://github.com/inspect-js/is-callable/blob/main/index.js) package. – pilchard May 20 '22 at 15:03
  • "`typeof new CallableClass` will still be `function`." I never said otherwise: in fact suggested that it would be. – Ben Aston May 20 '22 at 15:05
  • 1
    Bringing us back to @deceze comment... – pilchard May 20 '22 at 15:05
  • 1
    Does this answer your question? [Check if a variable is of function type](https://stackoverflow.com/questions/5999998/check-if-a-variable-is-of-function-type) – H. Almidan May 20 '22 at 15:09
  • @H.Almidan That is a different question. – Ben Aston May 20 '22 at 15:11
  • You could check if the object has the `apply` or `call` method without having to invoke the function. This is a less canonical approach to `typeof fn === 'function'` but would work...in most cases . – Nickofthyme May 20 '22 at 15:38
  • 1
    @Nickofthyme That merely tests for the presence of that function on a property on an object on the prototype chain of the object under test. It doesn't test whether the object is callable. I can put `Function.prototype.call` on the prototype chain of any object I like. – Ben Aston May 20 '22 at 15:40

1 Answers1

0

Yes.

typeof was added to the language in JavaScript 1.1 (codified June, 1997).

A predicate to determine callability was rejected in favour of a tweaked typeof (to return 'function' for callable objects) on the basis of parsimony. A callable object was defined as being "native" (presumably not "host" (eg browser) or "foreign" (eg. Java interop.)?), and implementing the internal [[Call]] method.

Thus: typeof returns 'object' for every native object in JavaScript, except callable native objects, for which it returns 'function'.

Note that:

From the JavaScript 1.1 specification:

typeof entry in JavaScript 1.1 specification

Since the internal [[Call]] method is not directly visible to userland code; and since [[Call]] cannot be configured on an existing object by simply running the Function constructor against an existing object; and since adding Function.prototype to the prototype chain of an existing object is insufficient, there are only two ways of determining callability:

  1. Attempt to run the object as a function
  2. Use typeof === 'function'

Reference:

Me:

Was this because there was no other userland way to distinguish between a callable object created using function foo(){} and a non-callable object that merely inherited from Function.prototype? Or that perhaps there was a way, but that it was inconvenient?

Brendan Eich:

Yes, and we anticipated foreign (Java, lol) objects and "host objects" that had callable objects which weren't native JS functions. I was adding typeof in Netscape 3 (JS1.1) so rather than a callable predicate, parsimonious to extend typeof slightly.

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