3

I am looking for a way to construct a function that has some inheritance.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/prototype

What I am looking for is an object that is a function that can be instantiated in a program, but that has new properties attached to it's prototype.

So, what we shouldn't do is this:

Function.prototype.x = function(){

};

Function.prototype.y = function(){

};

so what I want to do is something like:

const proto = Object.create(Function.prototype);

proto.x = function(){};

proto.y = function(){};

however, at some point later in the program, I would like to actually define the function body for proto, so that I can actually call proto like a function:

proto();

is there a way to do this? The above definitely does not work :)

This is a little closer, and the error message is telling:

function F(){

}

F.prototype = Function.prototype;

var f = new F();

f.apply(null);

Run the above and we get:

TypeError: Function.prototype.apply was called on [object Object], which is a object and not a function at Object. (/Users/amills/WebstormProjects/oresoftware/suman/exp7.js:15:3) at Module._compile (module.js:541:32) at Object.Module._extensions..js (module.js:550:10) at Module.load (module.js:458:32) at tryModuleLoad (module.js:417:12) at Function.Module._load (module.js:409:3) at Function.Module.runMain (module.js:575:10) at startup (node.js:160:18) at node.js:449:3

Alexander Mills
  • 90,741
  • 139
  • 482
  • 817
  • I've tried this, the further you go down this road, the more hacky it gets. What do you want to achieve with that? Why does the instance have to be a function? why can't you simply attach the function to the instance? – Thomas Jun 04 '16 at 00:31
  • I believe you, even given the little amount of experimentation that I have done - I am creating a library/API. Inheritance just means more performance, because prototypes are shared objects - what I want is an object that is a function but whose prototype is shared, but is not the function prototype :) probably not going to happen :( – Alexander Mills Jun 04 '16 at 00:35
  • In compatible engines, you can define a `class` that `extends Function` ([support](https://kangax.github.io/compat-table/es6/#test-Function_is_subclassable)). – Jonathan Lonowski Jun 04 '16 at 00:39
  • @JonathanLonowski could you perhaps show an example of that? If ES6 can do it, why wouldn't ES5 be able to? – Alexander Mills Jun 04 '16 at 00:41
  • 1
    @AlexMills A function is recognized by an internal property, [`[[Call]]`](http://www.ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist). This isn't inherited from a prototype and `Object.create()` doesn't have any mechanism to define it. – `class` works by invoking the `Function` constructor through `super()`, which does set `[[Call]]`. – Jonathan Lonowski Jun 04 '16 at 00:49
  • 1
    A possible alternative could be to [change the function's prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf) after it's been created – `var foo = function () {}; Object.setPrototypeOf(foo, proto);`. – Jonathan Lonowski Jun 04 '16 at 00:53
  • @JonathanLonowski yeah I was thinking that, I will experiment – Alexander Mills Jun 04 '16 at 00:54
  • @JonathanLonowski changing the "_____proto_____" of a function after it's declared/created, seems to work, but I wonder if there are any caveats? – Alexander Mills Jun 04 '16 at 00:57
  • You're painting yourself into a corner. Through the usage of internal Classes in modern JS-engines you don't even get any performance or memory-gain out of this. On the other hand, you complicate the instantiation-process wich makes this part slower. And the worst of all, you might confuse the users of your Lib, wich usually leads to more errors. – Thomas Jun 04 '16 at 01:02
  • by internal classes you mean Function? I agree with what you're saying. This is internal to my library and is not anywhere close to the API itself, otherwise I definitely wouldn't mess with it. – Alexander Mills Jun 04 '16 at 01:04
  • I added an answer, see if you agree with the mechanics, if not the motivation. – Alexander Mills Jun 04 '16 at 01:05
  • It's an interesting question and desirable behavior but I tend to agree with @Thomas at least for ES5. Main reason I gave an ES6 answer was that you tagged it with `node.js`, so it would seem like ES5 would be a non-issue. Are you stuck on an ES5-based version of Node? If so, I'm pretty sure this question has been asked a number of times here. –  Jun 04 '16 at 12:04
  • Given you are using nodejs, you might be interested in [How to extend `Function` with ES6 classes?](http://stackoverflow.com/q/36871299/1048572) – Bergi Jun 04 '16 at 22:13

1 Answers1

1

The right way to do this is as follows!

step 1

create an Object which inherits from Function.prototype

const obj = Object.create(Function.prototype);  // inherits many properties, etc

step 2

later in your program declare the function

const f = function(){};

step 3

set the __proto__ of f to obj

Object.setPrototypeOf(f,obj); which is basically equivalent to f.__proto__ = obj;

....this seems to work without any problems, thanks for everyone's help!

Alexander Mills
  • 90,741
  • 139
  • 482
  • 817