This is a short and simple trick for working with classes in JavaScript. Many programmers including myself that are comfortable with Object-Oriented Programming concepts are used to working with classes.
If you fall into this category then you probably like using classes in JavaScript like this:
class MyClass {
constructor(){
this.message = "hello there"
}
printMessage = () => {
console.log(this.message) // valid prints "hello there"
}
}
Even though this is just syntax sugar on top of regular prototype-based inheritance. I find it easier to read.
One specific issue I have with the syntax of JavaScript classes is how members of a class, like message
, are referenced in member functions.
In the example above we have to use this.message
in printMessage
even though printMessage
is a member MyClass
instance to reference message
.
It would be a lot nicer to just do the following:
class MyClass {
constructor(){
this.message = "hello there"
}
printMessage = () => {
console.log(message) // invalid prints undefined
}
}
It's a contrived example I know. But typing and reading this.message
over and over and over again can be quite cumbersome if it is used in a function enough.
Then I realized that we can just use destructuring on the this
object of member functions.
class MyClass {
constructor(){
this.message = "hello there"
}
printMessage = () => {
const {message} = this
console.log(message)
}
}
Reference Types and Primitive Types
This approach has some drawbacks and gotchas when dealing with reference types and primitive types. It's good to be aware of them if you decide to do this.
Let's look at this class definition:
class MyClass {
constructor(){
this.message = "hello there" // primitive type
this.items = [1, 2, 3] // reference type
}
printMessageMutable = () => {
// copies the value of this.message into message
let {message} = this
console.log(this.message) // prints "hello there"
console.log(message) // prints "hello there"
// will not update this.message
message = "there hello"
console.log(this.message) // prints "hello there"
console.log(message) // prints "there hello"
}
printMessageImutable = () => {
const {message} = this
console.log(message) // prints "hello there"
}
printItemsMutable = () => {
// creates mutable a copy of the reference to this.items
let {items} = this
// both items and this.items reference the same array
items.push(42)
console.log(items) // prints [1, 2, 3, 42]
console.log(this.items) // prints [1, 2, 3, 42]
// now items and this.items reference different arrays
items = [4, 5, 6]
console.log(items) // prints [4, 5, 6]
console.log(this.items) // prints [1, 2, 3, 42]
}
} // MyClass
In printMessageMutable
we create a local copy of this.message
. That means that any changes to message
in the function will not be reflected in this.message
. If we needed to update this.message
in printMessageMutable
this might not be the best place to use destructuring on this
.
In printMessageImutable
we create a constant copy of this.message
. So we are only ever planning on using the value of this.message
and can't try to update it using the local variable message
. This is a great case for using object destructuring on this
.
In printItemsMutable
we are updating an array. Arrays are reference types in JavaScript. When we call items.push(42)
both items
and this.items
are referencing the same array. Because of this, both items
and this.items
will be updated. Later we set the local variable items
to a new array [4, 5, 6]
. Now when we print items
and this.items
we get different values. That's because this.items
is still pointing to the old array initially set in the constructor.
Conclusion
That's it. I just think it's nice to be able to drop the this.
especially if a member variable is used a lot in one function. However, it won't be appropriate for all use cases.
Thanks for reading, let me know you disagree!
Top comments (2)
I've considered this myself. It can definitely make code feel more readable but there are a couple of drawbacks:
this.myVar = newValue
I'm used to representing members with a
_
at the end of their name, something likethis.message_
. I'm also used writing c++ which does not require the use ofthis
to access members. So I have some biases that don't necessarily fit with the normal conventions or language JavaScript 🤷♂️.And you're right there is some nuance for value types and reference types. I'm updating the post now to clarify them!