Using arrow functions on a class with babel transpiles it so the definition is bound in the constructor. And so it is not in the prototype and it is not available via super
when inheriting. It is also not as efficient when scaling by creating many instances.
There are more blog posts on this topic, but I just wanted to know the difference in how mobx.action.bound is handled compared to arrow functions when using babel.
Comparing the two:
class Example {
test = () => {
console.log(this.message)
}
}
class Example {
@action.bound
test() {
console.log(this.message)
}
}
There are 2 variables @action
and @action.bound
have an effect on:
this
is bound in the resulting function.To summarize, these are the rules:
@action
preserves the original function's binding and prototype-inclusion. If the original function is not bound, the result will not be, and vise versa. And if the original function is not in the prototype, the result will not be, and vise versa.@action.bound
will always result in a function which is bound, and which is in the prototype.You can easily test this like so:
class Store {
unbound() {
console.log('unbound', this)
}
arrow = () => {
console.log('arrow', this)
}
}
const storeInstance = new Store()
const unbound = storeInstance.unbound
const arrow = storeInstance.arrow
unbound()
arrow()
// console displays:
// unbound undefined
// arrow Store
Now let's try adding @action
:
class Store {
@action
unbound() {
console.log('unbound', this)
}
@action
arrow = () => {
console.log('arrow', this)
}
}
const storeInstance = new Store()
const unbound = storeInstance.unbound
const arrow = storeInstance.arrow
unbound()
arrow()
// console still displays:
// unbound undefined
// arrow Store
Now let's try adding @action.bound
:
class Store {
@action.bound
unbound() {
console.log('unbound', this)
}
@action.bound
arrow = () => {
console.log('arrow', this)
}
}
const storeInstance = new Store()
const unbound = storeInstance.unbound
const arrow = storeInstance.arrow
unbound()
arrow()
// console now displays:
// unbound Store
// arrow Store
As you can see, @action
maintains the function's bindings (or lack of binding). Meanwhile, @action.bound
will always return a bound function, thus turning an unbound function into a bound one, and an already bound function will remain bounded.
As for your concern about inheritance, here is the Store
definition:
class Store {
unbound() {}
arrow = () => {}
@action unboundAction() {}
@action.bound unboundActionBound() {}
@action arrowAction = () => {}
@action.bound arrowActionBound = () => {}
}
And this is what the storeInstance looks like:
As you pointed out, arrow = () => {}
is not part of the prototype. And to answer your question, @action arrow = () => {}
will not result in a function which is in the prototype. It looks like @action
preserves the previous behavior. However, @action.bound
will always result in a function which is in the prototype.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With