За да избегнем недоразумения, нека първо се споразумеем за значението на определени думи. Следните значения не са общоприети, аз само ги предлагам като контекст за този въпрос.
- функция -- екземпляр на
Function
. Той има процедура, свързана с него. - обект -- екземпляр на всеки друг клас. Няма процедура, свързана с него.
- процедура -- блок от код, който може да бъде изпълнен. В JS процедурите могат да бъдат намерени само свързани с функции.
- метод -- функция, която се съхранява в свойство на друг обект. Методите се изпълняват в контекста на техните хост обекти.
В JavaScript е обичайно обектите да се персонализират със свойства и методи, докато функциите не. С други думи, ако видите това в кода:
foo.bar // Accessing a property on an instance
foo.baz() // Calling a method on an instance
тогава foo
почти със сигурност е обект, а не функция.
Но технически функциите не се различават от обектите (всъщност функциите в JS се считат за обекти, това е само аз ги разграничавам за яснота).
И ако направите това:
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
...ще работи добре.
Бих искал да въведа още два термина, за да разберете какво имам предвид. Не се опитвам да променя правилата на JavaScript тук, просто искам да бъда разбран.
- функционален обект -- функция, която се използва като обект: има свои собствени свойства и/или методи.
- основен метод -- процедурата на самия функционален обект, за разлика от методите, съхранени като свойства на функционален обект.
Много JS библиотеки предлагат функционални обекти, например jQuery и LoDash. т.е. можете да направите както $()
, така и $.map()
.
Добре, сега към въпроса.
Бих искал да мога да създавам свои собствени функционални обекти със следните изисквания:
- Трябва да мога да използвам декларацията ES2015
class
, за да опиша класа на моя функционален обект. Или поне начинът на описване на класа трябва да е достатъчно удобен. Императивното присвояване на свойства и методи на функция не е удобно. - Основният метод на моя функционален обект трябва да се изпълнява в същия контекст като другите му методи.
- Основният метод и други методи трябва да бъдат обвързани с един и същ екземпляр. Например, ако имам основен метод и нормален метод, които и двата правят
console.log(this.foo)
, тогава присвояването наmyFunctionObject.foo
трябва да промени поведението както на основния метод, така и на другия метод.
С други думи, искам да мога да направя това:
class Foo {
constructor () { this.bar = 'Bar'; }
mainMethod () { console.log(this.bar); }
anotherMethod () { console.log(this.bar); }
}
...но екземпляр на Foo
трябва да има foo.mainMethod()
достъпно просто като foo()
.
И извършването на foo.bar = 'Quux'
трябва да промени поведението както на foo()
, така и на foo.anotherMethod()
.
Може би има начин да го постигнете с class Foo extends Function
?