class Aa {
methodA() {
console.log('welcome to method a')
}
methodB() {
console.log('welcome to method b')
// methodA() // Fails!! Uncaught ReferenceError: methodA is not defined
this.methodA() // Works because of this.
}
}
let myclass = new Aa()
myclass.methodB()
What is the best way to concisely explain why you need to use 'this' when calling another method of the class that you are already in?
Intuition might say, well if JS knows that I'm using a method of a class, then it knows about that class...because I'm using it's method.....so why can't it find another method of that same class without me telling it...yeah 'this' same place!
By way of contrast, functions can do it with no problem:
function a() {
console.log('welcome to function a')
}
function b() {
console.log('welcome to function b')
a() // works without any sort of 'scope help'
}
b()
I want to be able to explain it without getting people distracted with needing to know the deepest reasons for it. If possible, ha!
Part of me just wants to say, "That's how JS classes work. You gotta 'this'-ify things."
In order to understand why we need to explicitly reference this
in Javascript classes, we first need to understand what the this
reference points to in ordinary functions.
In Javascript the this
keyword is always a reference to the object that called the function.
Consider the following:
const obj1 = {
foo() { console.log(this); }
}
obj1.foo(); // "this" will reference "obj1"
Nothing strange here, this
is a reference to the object where it was defined obj1
.
Now think about what would happen if we took the function foo
and "removed" it from the object. Since this
is a reference to the object that called the function, what should this
be if the function doesn't belong to an object?
const obj1 = {
foo() { console.log(this); }
}
const foo = obj1.foo;
foo(); // "this" will reference "window"
This is were things start to become strange, this
is actually a reference to the global
object. This is because everything in Javascript is an object, even the root level of a file. In the browser this global object is called the window
object.
Now consider what happens if we reattache the method to another object?
const obj1 = {
foo() { console.log(this); }
}
const foo = obj1.foo;
const obj2 = {};
obj2.foo = foo;
obj2.foo(); // "this" will reference "obj2"
The same rules apply here, since the function now belongs to an object again the this
reference points to obj2
.
Fist of all Javascript doesn't actually have classes. A js class in just a different way of writing a prototype.
Lets start by writing a simple class.
class Foo {
constructor() { console.log("I'm a Class constructor") }
log() { console.log("I'm a Class method") }
}
const obj1 = new Foo(); // I'm a Class constructor
obj1.log(); // I'm a Class method
Now lets write the same "class" as a prototype.
function Bar() {
console.log("I'm a Prototype constructor")
}
Bar.prototype = {
log() {
console.log("I'm a Prototype method")
}
}
const obj2 = new Bar(); // I'm a Prototype constructor
obj2.log(); // I'm a Prototype method
These two ways of writing inheritance (classes & prototypes) are the same thing in Javascript.
So as we can more clearly see in the prototype implementation the "class methods" are actually just an object assigned to the prototype of a function.
Now that we know about this
and about classes / prototypes
we can see that a class method is actually just a function on an object and that this
refers to the the object that called the function. So if we want to reference another function on the same object we should do so by referencing it through the this
reference.
class Aa {
methodA() {
console.log('welcome to method a')
}
methodB() {
console.log('welcome to method b')
this.methodA()
}
}
const myclass = new Aa()
myclass.methodB()
It is confusing mostly because Javascript has a long history of trying to fit the square peg of prototypes into the round hole of classes. A lot of things that make sense in traditional object-oriented languages only lead to confusion in javascript.
Your (very reasonable) intuition goes off the rails here:
Intuition might say, well if JS knows that I'm using a method of a class, then it knows about that class...because I'm using it's method
methodA()
and methodA()
are just functions. They don't know anything about where they were defined. What they know is how they were called. this
is the key to tying how the function is called to the rest of the class. Consider this example:
class Aa {
methodA() {console.log('welcome to method a')}
methodB() {
console.log('welcome to method b')
this.methodA() // Works because of this.
}
}
let obj = {
methodA() { console.log("welcome to imposter A")}
}
let myclass = new Aa()
obj.methodB = myclass.methodB // take a reference to methodB and add it a different obj
console.log("Same?",obj.methodB === myclass.methodB)
// identical function but it has no idea
// it "belongs" to myclass. Called from a different context
// it acts like a normal function (because it is)
obj.methodB()
The function obj.methodB
doesn't know it belongs to class Aa
. The only thing the relates it to the class is the way it's called and the way it's called determines the value of this
. So this
(and the prototype chain) is the glue that holds the whole scheme together.
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