On Sun, Jan 27, 2019 at 10:46 PM Ranando King <king...@gmail.com> wrote:
> Jordan's right. This one is best handled by a function. But if there is > some reason you need to create callable objects, it's still doable, even > with ES as-is. Just extend your classes from something like this: > > ```js > class Callable { > constructor(defaultFn) { > return (...args) => { return defaultFn.call(this, ...args); }; > } > } > ``` > Any class extending this will have instances that are functions. So using > your UserCreator class... > > ```js > class UserCreator extends Callable { > constructor(repository) { > super(this.create); > this.repository = repository; > } > > create(name) { > return this.repository.createUser(name); > } > } > ``` > Can't you just use a function object? function UserCreator(repository) { if( !(this instanceof UserCreator ) ) return new UserCreator(repostiory); var creator = function xyz(name) { return { repo: repository, user: name } }: creator.repository = repository; creator.create = creator return creator; } > > Now `new UserCreator(someRepo)(someName)` is the same as `new > UserCreator(someRepo).create(someName)`. > both of the above also work that way. > > On Sun, Jan 27, 2019 at 11:35 PM Jordan Harband <ljh...@gmail.com> wrote: > >> Something that can be invoked has a `[[Call]]` slot, and is `typeof` >> "function". >> >> Adding a Symbol that makes something callable would have a number of >> effects - it would make `typeof` (one of the most robust operations in the >> language) unsafe, because it would have to access the Symbol method, which >> could be a throwing getter (or even one that just logs how many typeofs are >> called on it). Additionally, it would mean any object could become >> callable, and any function could be made *un* callable. >> >> This seems like a pretty large change, solely to avoid "classes with a >> single method", which arguably should just be a function in the first place. >> >> On Sun, Jan 27, 2019 at 4:05 PM Brasten Sager <bras...@brasten.me> wrote: >> >>> Apologies if this has been raised before. I was unable to locate >>> anything similar. >>> >>> Any thoughts or ideas on this proposal would be appreciated! >>> >>> Original: >>> https://gist.github.com/brasten/f87b9bb470973dd5ee9de0760f1c81c7 >>> >>> -Brasten >>> >>> — >>> >>> # Proposal: Default object method # >>> >>> Objects w/ default method can be invoked like a function. >>> >>> ## Problem ## >>> >>> Objects that are well constrained (single responsibility) >>> can tend to end up with a single method, or at least a single method >>> that is important to most consumers. These methods tend to be named >>> by either verbing the class name (eg. `UserCreator.create()`) or with >>> some generic `handle` / `perform` / `doTheObviousThing`. >>> >>> Whatever the name, downstream consumers of the object end up coupled to >>> two implementation details: >>> >>> 1) this thing-doer is an object and not a function >>> 2) this thing-doer's doing method is called `X` >>> >>> ### Example ### >>> >>> Here we are going to create an object that can be used to >>> create a user later. Note that downstream consumers will only >>> care that this object does one thing: create a user. While it >>> make have other methods eventually for use in some limited >>> contexts, creating a user is its primary (and often sole-) >>> responsibility. >>> >>> ```js >>> class UserCreator { >>> constructor(repository) { >>> this.repository = repository; >>> } >>> >>> create(name) { >>> return this.repository.createUser(name); >>> } >>> } >>> >>> const userCreator = new UserCreator(userRepository); >>> ``` >>> >>> At this point, the `userCreator` is just a single-method object. >>> It is useful for injecting into other objects that may need to >>> create a user. But the fact that the `userCreator` is an object >>> with a single useful method is an implementation detail to which >>> consumers become coupled. >>> >>> ```js >>> >>> // Consumer of `userCreator`. Although this could itself be a >>> // good example of a "UserCreator"-like object (due to `.handle()`). >>> // >>> class UserSignupHandler { >>> constructor(userCreator) { >>> this.userCreator = userCreator; >>> } >>> >>> handle(userName) { >>> // UserSignupHandler is aware of ".create" when it really doesn't >>> have to be. >>> // >>> return this.userCreator.create(userName); >>> } >>> } >>> >>> const handler = new UserSignupHandler(userCreator); >>> ``` >>> >>> Notably, if we were to change the implementation of UserCreator later to >>> be >>> a pure function, we would have to change all consumers of UserCreator >>> when >>> conceptually it shouldn't be needed. There is still a thing-doer that has >>> the same input/output. >>> >>> >>> ## Proposed Solution ## >>> >>> An object instance can have a default method. This would allow an >>> object to be "invoked" exactly like a function, hiding the implementation >>> detail from consumers. >>> >>> Note that there are several ways to define how the default method is >>> determined, and this proposal is less concerned with this aspect than >>> with >>> what it looks like to invoke the object. We will demonstrate an option >>> here, >>> but alternatives are welcome. >>> >>> ```js >>> // This particular implementataion would use a Symbol. >>> // >>> >>> class UserCreator { >>> constructor(repository) { >>> this.repository = repository; >>> } >>> >>> [Symbol.apply](name) { >>> return this.repository.createUser(name); >>> } >>> } >>> >>> const userCreator = new UserCreator(userRepository); >>> >>> class UserSignupHandler { >>> constructor(userCreator) { >>> // NOTE: at the consumer, it almost makes more sense to >>> // name these with action verbs, as is done here. >>> // >>> this.createUser = userCreator; >>> } >>> >>> handle(userName) { >>> // UserSignupHandler is no longer coupled to the implementation >>> details it doesn't need. >>> // >>> return this.createUser(userName); >>> } >>> } >>> >>> const handler = new UserSignupHandler(userCreator); >>> ``` >>> >>> _______________________________________________ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> _______________________________________________ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > _______________________________________________ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss >
_______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss