To avoid misunderstanding, let's agree on the meaning of certain words first. The following meanings are not universally accepted ones, I only suggest them as a context for this question.
- function -- an instance of
Function
. It has a procedure associated with it. - object -- an instance of any other class. Does not have a procedure associated with it.
- procedure -- a block of code that can be executed. In JS procedures can only be found associated with functions.
- method -- a function that is stored in a property of another object. Methods execute in their host objects' contexts.
In JavaScript it is common that objects are customized with properties and methods, while functions don't. In other words, if you see this in code:
foo.bar // Accessing a property on an instance
foo.baz() // Calling a method on an instance
then foo
is almost certainly an object and not a function.
But technically functions are no different from objects (in fact, functions in JS are considered to be objects, it's just me distinguishing them for clarity).
And if you do this:
const foo = function () { /*...*/ }
foo() // Calling the function's procedure
foo.bar // Accessing a property on the function
foo.baz() // Calling a method on the function
...it will work just fine.
I would like to introduce two more terms so that you can understand what I mean. I'm not trying to alter the rules of JavaScript here, just want to be understood.
- function-object -- an function that is used as an object: has its own properties and/or methods.
- main method -- the procedure of a function-object itself, as opposed to methods stored as properties on a function-object.
Many JS libraries offer function-objects, for example jQuery and LoDash. I. e. you can do both $()
and $.map()
.
Okay, now to the matter.
I would like to be able to create my own function-objects with the following requirements:
- I should be able to use the ES2015
class
declaration to describe the class of my function-object. Or at least the way of describing the class should be convenient enough. Imperatively assigning properties and methods to a function is not convenient. - The main method of my function object should execute in the same context as its other methods.
- The main method and other methods should be bound to the same instance. For example if I have a main method and a normal method that both do
console.log(this.foo)
, then assigning tomyFunctionObject.foo
should modify the behavior of both the main mehtod and the other method.
In other words, I want to be able to do this:
class Foo {
constructor () { this.bar = 'Bar'; }
mainMethod () { console.log(this.bar); }
anotherMethod () { console.log(this.bar); }
}
...but an instance of Foo
should have foo.mainMethod()
available simply as foo()
.
And doing foo.bar = 'Quux'
should modify the behavior of both foo()
and foo.anotherMethod()
.
Maybe there's a way to achieve it with class Foo extends Function
?