Isiah: good find. I was just being sloppy to get the idea across. J. Decker: The code I gave was just an example of how to do it if it was for some reason absolutely necessary to use `class`. I don't see the need and would either tend toward your approach, or just somehow refactor away the need for the odd construction.
On Mon, Jan 28, 2019 at 6:46 AM J Decker <[email protected]> wrote: > > > On Sun, Jan 27, 2019 at 10:46 PM Ranando King <[email protected]> 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 <[email protected]> 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 <[email protected]> >>> 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 >>>> [email protected] >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>> _______________________________________________ >>> es-discuss mailing list >>> [email protected] >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> _______________________________________________ >> es-discuss mailing list >> [email protected] >> https://mail.mozilla.org/listinfo/es-discuss >> >
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

