23. Object Methods & this Keyword
JavaScript provides object methods to define functions as properties of an object. One of the most important concepts in object methods is the this keyword, which refers to a specific object.
Why Are Object Methods Important?
Without methods, you'd have to create separate functions and call them manually. With methods, an object's data and behavior are combined in one place — the principle of encapsulation.
// Without methods
const student = { name: "Mike", gpa: 3.75 };
function getStudentInfo(m) {
return `${m.name} - GPA: ${m.gpa}`;
}
// With methods
const student = {
name: "Mike",
gpa: 3.75,
getInfo() {
return `${this.name} - GPA: ${this.gpa}`;
}
};
console.log(student.getInfo()); // "Mike - GPA: 3.75"
Code Example
How to Define Methods
const student = {
name: "Anna Lee",
studentId: "2024001",
gpa: 3.85,
// Method shorthand (recommended)
getInfo() {
return `${this.name} (${this.studentId})`;
},
// Old way with a property
setGPA: function(grade) {
if (grade >= 0 && grade <= 4) {
this.gpa = grade;
return `GPA for ${this.name} updated: ${this.gpa}`;
}
return "GPA must be between 0 - 4";
},
// Calculate the classification
calculateClassification() {
if (this.gpa >= 3.5) return "Cum Laude";
if (this.gpa >= 3.0) return "Very Satisfactory";
if (this.gpa >= 2.5) return "Memuaskan";
return "Cukup";
}
};
console.log(student.getInfo()); // "Anna Lee (2024001)"
console.log(student.calculateClassification()); // "Cum Laude"
console.log(student.setGPA(3.2)); // "GPA for Anna Lee updated: 3.2"
this in Various Contexts
The this keyword changes its value depending on the calling context:
// 1. Global context
console.log(this); // window (browser) / globalThis (Node.js)
// 2. Function context (sloppy mode)
function checkThisGlobal() {
console.log(this); // window (not undefined!)
}
checkThisGlobal();
// 3. Function context (strict mode)
function checkThisStrict() {
"use strict";
console.log(this); // undefined
}
checkThisStrict();
// 4. Object method — this refers to the object
const lecturer = {
name: "Dr. John",
greet() {
console.log(this); // the lecturer object
console.log(`Hello, I am ${this.name}`);
}
};
dosa.greet();
// 5. Arrow function — this is inherited from the outer scope
const myClass = {
name: "TI-2024-A",
students: ["Mike", "Anna", "John"],
display() {
// the arrow function inherits this from display()
this.students.forEach((name) => {
console.log(`is a student of myClass ${this.name}`);
});
}
};
myClass.display();
// 6. Constructor / Class
class Student {
constructor(name) {
this.name = name; // this refers to the new instance
}
}
const student = new Student("Mike");
console.log(student.name); // "Mike"
this in Event Listeners
// In an event listener, this refers to the clicked element
document.getElementById("btnProfile").addEventListener("click", function() {
console.log(this); // the button element itself
console.log(this.id); // "btnProfile"
});
// Arrow function in an event listener — this is NOT the element
document.getElementById("btnProfile").addEventListener("click", () => {
console.log(this); // window, not the element!
// Avoid arrow functions in event listeners if you need this
});
call(), apply(), bind()
These three methods let us manipulate the value of this explicitly:
const major = {
name: "Computer Science",
capacity: 120,
classInfo(myClass, count) {
return `${this.name} - Class ${myClass}: ${count}/${this.capacity} students`;
}
};
const majorSystems = {
name: "Information Systems",
capacity: 90
};
// call() — invoke immediately with a new this, arguments passed individually
console.log(major.classInfo.call(majorSystems, "A", 45));
// "Information Systems - Class A: 45/90 students"
// apply() — like call(), but arguments in an array
console.log(major.classInfo.apply(majorSystems, ["B", 60]));
// "Information Systems - Class B: 60/90 students"
// bind() — create a new function with this already set
const infoMajorSystems = major.classInfo.bind(majorSystems);
console.log(infoMajorSystems("C", 30));
// "Information Systems - Class C: 30/90 students"
Code Explanation
| Concept | Explanation |
|---|---|
| Method shorthand | name() is more concise than name: function() |
this in a method |
Refers to the object that owns the method |
this in an arrow function |
Inherits this from the parent scope (lexical this) |
this in an event listener |
Refers to the event's target element |
call() |
Invoke a function with a new this + arguments directly |
apply() |
Invoke a function with a new this + arguments in an array |
bind() |
Create a new function with a permanent this (does not invoke immediately) |
Differences Between call, apply, and bind
call() → executes immediately, arguments: call(this, arg1, arg2)
apply() → executes immediately, arguments: apply(this, [arg1, arg2])
bind() → returns a new function, arguments: bind(this, arg1, arg2)
Real-World Examples
A student data management system in a campus portal:
const campusDatabase = {
students: [],
addStudent(student) {
this.students.push({
...student,
getInfo() {
return `${this.name} | ${this.studentId} | GPA: ${this.gpa}`;
},
getClassification() {
if (this.gpa >= 3.5) return "Cum Laude";
if (this.gpa >= 3.0) return "Very Satisfactory";
return "Memuaskan";
}
});
},
findByStudentID(studentId) {
return this.students.find(m => m.studentId === studentId);
},
getStatistics() {
const total = this.students.length;
const average = total > 0
? this.students.reduce((sum, m) => sum + m.gpa, 0) / total
: 0;
return { total, average: average.toFixed(2) };
}
};
// Add students
campusDatabase.addStudent({
name: "Mike Johnson",
studentId: "2024001",
gpa: 3.75
});
campusDatabase.addStudent({
name: "Anna Reed",
studentId: "2024002",
gpa: 3.20
});
// Find & display
const mike = campusDatabase.findByStudentID("2024001");
console.log(mike.getInfo()); // "Mike Johnson | 2024001 | GPA: 3.75"
console.log(mike.getClassification()); // "Cum Laude"
// Statistics
console.log(campusDatabase.getStatistics());
// { total: 2, average: "3.48" }
Another Example: Button Handlers with bind()
const studentList = [
{ name: "Mike", studentId: "2024001" },
{ name: "Anna", studentId: "2024002" },
{ name: "John", studentId: "2024003" }
];
function showDetails() {
document.getElementById("detail").textContent =
`${this.name} (${this.studentId})`;
}
studentList.forEach(m => {
const btn = document.createElement("button");
btn.textContent = m.name;
btn.addEventListener("click", showDetails.bind(m));
document.getElementById("container").appendChild(btn);
});
Conclusion
- Method shorthand is the modern way to define methods in an object.
thischanges depending on the context: method → owning object; arrow function → parent scope; event listener → target element.call()andapply()invoke a function with a newthis(apply uses an array).bind()returns a new function with a permanentthis.- Use arrow functions inside methods to safely access the parent
this.