How can I make constructor for callable object in JavaScript?
I've attempted various ways, like following. The example there is just shortened example of actual object.
function CallablePoint(x, y) {
function point() {
// Complex calculations at this point
return point
}
point.x = x
point.y = y
return point
}
This works at first, but the object it creates isn't instance of CallablePoint
, so it doesn't copy properties from CallablePoint.prototype
and says false
on instanceof CallablePoint
. Is it possible to make working constructor for callable object?
Turns out it's actually possible. When the function is created, either by using function
syntax, or Function
constructor, it gets internal [[Call]]
property. It isn't a property of function itself, but rather property that any function gets when constructed.
While that only means that anything with [[Call]]
could be only Function
when it's constructed (well, there is one exception – Function.prototype
itself that doesn't inherit from Function
), that doesn't mean it cannot become something else later, while preserving [[Call]]
property. Well, provided your browser isn't IE < 11.
The thing that allows changing the magic would be __proto__
from ES6, already implemented in many browsers. __proto__
is a magical property that contains current prototype. By changing it, I can make function that inherits from something that isn't Function
.
function CallablePoint(x, y) {
function point() {
// Complex calculations at this point
return point
}
point.__proto__ = CallablePoint.prototype
point.x = x
point.y = y
return point
}
// CallablePoint should inherit from Function, just so you could use
// various function methods. This is not a requirement, but it's
// useful.
CallablePoint.prototype = Object.create(Function.prototype)
First, the constructor for CallablePoint
makes a Function
(only Function
s are allowed to begin with [[Call]]
property. Next, I change its prototype, so it would inherit CallablePoint
. At this point I have a function that doesn't inherit from Function
(sort of confusing).
After I defined constructor for CallablePoint
s, I set the prototype of CallablePoint
to Function
, so I have CallablePoint
that inherits from Function
.
This way, the CallablePoint
instances have prototype chain: CallablePoint -> Function -> Object
, while still being callable. Also, because the object is callable, it has according to the specification, typeof
equal to 'function'
.