Constructor for callable object in JavaScript

Konrad Borowski picture Konrad Borowski · Sep 29, 2012 · Viewed 8.3k times · Source

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?

Answer

Konrad Borowski picture Konrad Borowski · Jun 14, 2013

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 Functions 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 CallablePoints, 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'.