Naftali
Naftali

Reputation: 146310

Is it possible for an object to also be a function?

In the vain of this question.

Is it at all possible for an object to also be a function.

For example I have the object person which is an instance of some object.

Is it possible for me to call person(...) and have some return come back to me?

This is where person has not been defined as a function to start with.

So for example I have the "class" Person:

class Person {
     // .. some class functions
}

Then I create a new one

let person = new Person();

Can I call person() and affect the actual object behavior? Or is that not possible at all and person itself will have to be defined as a function to begin with?

Upvotes: 1

Views: 134

Answers (1)

Jared Smith
Jared Smith

Reputation: 21926

Short answer, No. Yes! See proxy solution below.

In section 9.2.1 of the spec it outlines Function objects' internal [[Call]] property that allows that object to be called as a function. There is currently no way I know of to modify that property, i.e. make an object into a function after its creation. It will be possible with a fully compliant implementation of ES 2015 to subclass Function and have callable objects (currently works in FF, for example). Even then, I didn't try anything more than making a paper-thin layer over the Function constructor itself. However, ES 2015 also includes Proxies, and one of the proxy traps is 'apply'.

class Person {
  constructor(arg, body) {
    this.fn = function(a) { this.a = a; };
    return new Proxy(this, {
      apply: function(target, thisArg, args) {
        return target.fn.apply(target, args);
      }
    });
  }
}
var person = new Person();
person(3);
person.a; //3

Tested in Chrome 49. Fails in FF unless Person extends Function and makes a call to super:

class Person extends Function {
  constructor() {
    super();
    this.fn = function(a) { this.a = a; };
    return new Proxy(this, {
      apply: function(target, thisArg, args) {
        return target.fn.apply(target, args);
      }
    });
  }
}
var person = new Person();
person(3);
person.a;

According to MDN, the part about requiring the super call is correct at least (for subclasses) but I am unsure whether Proxies should let you call a non-function the way chrome lets you.

UPDATE

I opened another question about which behavior is correct. For those too lazy to follow a hyperlink the calling of a non-function is a bug in some specific versions of chrome that has since been fixed.

Upvotes: 1

Related Questions