3

I'm working on a project that involves constructing functions from other functions. I had the idea of writing a class to simplify things but I haven't been able to get it to work without resorting to using __proto__.

Here's basically what my vision is.

function MyFunction () {
    // ...
}
var myFn = new MyFunction();
myFn(); // executes without error
myFn instanceof MyFunction; // returns true

The following code does just that using __proto__

function MyFunction () {
    var fn = function () { return 'hello'; };
    fn.__proto__ = this;
    return fn;
}
var myFn = new MyFunction();
alert( myFn() ); // hello
alert( myFn instanceof MyFunction ); // true

Here's something I've tried using valueOf

function MyFunction () {
    this.fn = function () { return 'hello'; };
    this.valueOf = function () { return this.fn; };
}
var myFn = new MyFunction();
alert( myFn instanceof MyFunction ); // true
alert( myFn.valueOf()() ); // hello
alert( myFn() ); // error

And here's something else extending the function to contain all the properties of MyFunction.

function MyFunction () {
    this.foo = 'hello'
    var fn = function () { return 'hello'; };
    for ( var i in this ) {
        fn[ i ] = this[ i ];
    }
    return fn;
}
var myFn = new MyFunction();
alert( myFn() ); // hello
alert( myFn.foo ); // hello
alert( myFn instanceof MyFunction ); // false

I don't want to use __proto__ because it's non-standard. Also, this was kind of a freak idea, I'd really like to get it to work, but if it's not possible I'll live. But I guess my question is, is what I'd like to do possible?

1 Answer 1

3

Fascinating idea. I don't believe you can do it with standard ECMAScript yet, not even using ES5.

ES5 gives us better access to and control over the prototype, including providing a means of setting the prototype when creating objects (without having to go through constructor functions) with Object.create, but you can't construct functions via that mechanism. And that's what you would have to do, because instanceof uses the abstract spec [[HasInstance]] method, which is currently only implemented by functions, and the function implementation of it works by seeing if the object's underyling prototype ([[Proto]]) is === to the function's prototype property. The only standard way to set the object's underlying prototype is to create it via new MyFunction or via Object.create, and neither mechanism creates a function object.

ES.next may make this possible. There's a proposal that's been promoted to "harmony" status (so, fairly advanced) for a "set prototype operator", <|, which is intended to solve many of the problems currently solved via __proto__. One of the things it's for is "Setting the prototype of a function to something other than Function.prototype". Using it (in its current form), your MyFunction would look something like this:

function MyFunction () {
  return MyFunction.prototype <| function () { return 'hello'; };
}
MyFunction.prototype = Object.create(Function.prototype);

That last bit is to make it that MyFunction.prototype is an object with the prototype Function.prototype, so that functions constructed via MyFunction have call, apply, bind, etc.

Sign up to request clarification or add additional context in comments.

1 Comment

Bummer, I also heard some form of __proto__ will be officially added in the next ES too. I guess I'm just ahead of my time :(. Oh well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.