The ECMAScript specification function IsCallable returns true iff its argument has a [[Call]] internal method. It is used in several places in the specification, such as in the definition of Array.prototype.toString
.
There is a similar specification function IsConstructor which returns true iff its argument has a [[Construct]] internal method.
Some JS objects, including most built-in functions such as escape
are callable but not constructible. Are there any which are constructible but not callable?
Note that both user-defined and built-in classes throw TypeError
when called as ordinary functions, but are still callable per the definition of IsCallable, as can be determined by seeing if Array.prototype.toString
will attempt to use them as the implementation of join
:
// {} is not callable, so toString falls back to Object.prototype.toString:
console.log('null:', Array.prototype.toString.apply({join: {}}));
// WeakMap is callable (but throws TypeError):
console.log('null:', Array.prototype.toString.apply({join: WeakMap}));
// User-defined classes also callable:
console.log('null:', Array.prototype.toString.apply({join: class Foo {}}));
Restatement: Is it possible for an object X to return true
for IsConstructor(X)
but false
for IsCallable(X)
? I.e., is it possible for an object X to have a [[Construct]]
internal method but not have a [[Call]]
internal method?
The ECMAScript spec isn't as clear-cut on this point as it could be.
(1) 6.1.7.2 "Object Internal Methods and Internal Slots" says:
A function object is an object that supports the [[Call]] internal method. A constructor (also referred to as a constructor function) is a function object that supports the [[Construct]] internal method.
From this we can conclude that if such an object X does exist, it is clearly not a 'function object' and thus also not a 'constructor'. I.e. IsConstuctor(X)
would return true
for an object that isn't deemed a 'constructor', which would be odd.
(2)
Note that in the clause that defines IsConstructor
, the preamble says that it determines whether its argument "is a function object with a [[Construct]] internal method", but the algorithm doesn't have an explicit check that the argument is a function object. This suggests that (the spec-writer thought that) having a [[Construct]] internal method is sufficient to guarantee that the argument is a function object, i.e. that it has a [[Call]] internal method.
(3)
The only point to having a [[Construct]]
internal method is to invoke it in the Construct
abstract operation. Similar to point (2), the preamble says that the operation "is used to call the [[Construct]] internal method of a function object", but the algorithm doesn't explicitly check that F
is a function object.
So I believe the answer is that, while the spec doesn't explicitly say that such objects can't exist, it fairly strongly implies/assumes that they don't.
UPDATE (2018-05-22):
6.1.7.2 "Object Internal Methods and Internal Slots" has now been modified to say (emphasis mine):
A function object is an object that supports the [[Call]] internal method. A constructor is an object that supports the [[Construct]] internal method. Every object that supports [[Construct]] must support [[Call]]; that is, every constructor must be a function object. Therefore, a constructor may also be referred to as a constructor function or constructor function object.
No, it’s not possible to create something that’s constructible but not callable. Everything that defines a [[Construct]] in the spec is a function except for proxies, which only have [[Construct]] when their target also does (9.15.4).
A Proxy exotic object only has a [[Construct]] internal method if the initial value of its [[ProxyTarget]] internal slot is an object that has a [[Construct]] internal method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With