Methods & this
Learn how functions stored on objects become methods, how this is chosen by the call shape, and how returning this powers method chaining.
- 01Write method shorthandStore functions on objects with
greet() {}and read sibling properties withthis. - 02Predict thisUse the object before the dot to explain
obj.method()calls, including one lost-this case. - 03Build chainsReturn
thisfrom mutating methods so calls can continue in a readable line.
Methods are functions that belong to objects
In Object basics, objects held data: names, scores, settings, and other properties. A property can also hold a function. When you call a function through an object, programmers call it a method.
const dog = { name: "Pixel", bark: function () { return dog.name + " says woof"; },}; console.log(dog.bark()); // Pixel says woofThat works, but dog.name is glued to one variable name. If the same function is shared with another object, hard-coding dog is too stiff. JavaScript gives methods a special word, this, for “the object this method is working with right now.”
Think of an object as a character card. It has facts, like a name, and skills, like bark or introduce. A method is one of those skills. When Pixel uses the skill, the word “my” points at Pixel.
- In real life: Pixel has the skill bark
- In JavaScript:
dog.bark()stores a function ondog - In real life: The skill can use Pixel’s name
- In JavaScript: The method reads
this.name - In real life: Another dog can use the same skill
- In JavaScript: The same function can be called as
nori.bark()
Where the analogy stops: A real skill is physically part of a dog. In JavaScript, the function value can be copied to another object or stored in a variable, which is why the call shape matters.
This lesson keeps to the core rule you need now: for a regular method call shaped like object.method(), this is the object before the dot, chosen when the call happens. The full rule book—call, apply, bind, global values, and strict-mode details—gets its own Stage 4 module.
Method shorthand
STEP THROUGHMost object methods use shorthand. Instead of writing bark: function () { ... }, write bark() { ... }. For everyday calls, they behave the same: both store a regular function in the bark property. One advanced difference is that shorthand methods are not meant to be used with new; constructors are the next lesson.
const oldStyle = { name: "Ada", greet: function () { return "Hi " + this.name; },}; const shorthand = { name: "Ada", greet() { return "Hi " + this.name; },};The important part is not the shorter spelling. It is the way the method reads nearby data. this.name means “the name property on the object currently using this method.”
Predict what dog.bark() prints. Then step through how method shorthand and this work together.
script
name: "Pixel", bark() { return this.name + " says woof"; },}; console.log(dog.bark());A method is a function value stored in a property. Objects do not permanently stamp ownership onto functions. That is why the next section focuses on the call shape, not on where the function was written.
this is decided at call time
INTERACTIVEHere is the rule to practice until it feels automatic: look at the actual call. In ada.introduce(), the object before the dot is ada, so this is ada. In lin.introduce(), the object before the dot is lin, so the same function sees a different this.
Choose a call shape, then step through the same function using a different this.
script
"use strict"; return "Hi, I am " + this.name;} const ada = { name: "Ada", introduce };const lin = { name: "Lin", introduce }; ada.introduce();The detached version is deliberately honest. Site modules are strict code, and the displayed snippet starts with "use strict". When the last line is speak(), there is no object before the dot. In strict code, this is undefined, so reading this.name throws a TypeError.
The word “my” changes meaning depending on who is speaking. If Ada says “my laptop,” it is Ada’s laptop. If Lin says the same words, it is Lin’s laptop. this works like that for method calls: its meaning comes from the caller right now.
- In real life: Ada says “my name”
- In JavaScript:
ada.introduce()makesthisbeada - In real life: Lin says “my name”
- In JavaScript:
lin.introduce()makesthisbelin - In real life: A quote with no speaker is confusing
- In JavaScript:
speak()has no object before the dot
Where the analogy stops: Human sentences have grammar and context. JavaScript uses a precise call rule for regular methods, and there are more call forms later.
Arrows, callbacks, and losing this
SORTArrow functions, from the Arrow functions lesson, have no own this. That makes them great inside a method when they should keep the method’s this, and risky as the method itself when you expected object.method() behavior.
| Shape | Gets object as this? | Good use |
|---|---|---|
greet() { return this.name; } | Yes, when called as obj.greet() | Object methods that read or change sibling properties |
greet: function () { return this.name; } | Yes, when called as obj.greet() | Older spelling of the same everyday idea |
greet: () => this.name | No | Rare as an object method; it keeps outer this instead |
() => obj.greet() | The arrow has no own this, but it performs a real method call | Callback wrapper to avoid losing this |
const user = { name: "Mina", regular() { return this.name; }, arrow: () => this.name,}; console.log(user.regular());console.log(user.arrow());const team = { prefix: "Team", names: ["Ada", "Lin"], labels() { return this.names.map((name) => this.prefix + ": " + name); },}; console.log(team.labels().join(", "));Callbacks are the other common trap. Passing ada.introduce to something like setTimeout passes the function value by itself. It is no longer called as ada.introduce(). A simple fix is an arrow wrapper: () => ada.introduce(). You will also learn bind in Stage 4.
dog.bark()app.user.sayName()const fn = dog.bark; fn()setTimeout(dog.bark, 0)setTimeout(() => dog.bark(), 0)const dog = { bark: () => this.name }
Sort each call shape by what happens to this. Focus on the object before the final dot.
Method chaining
INTERACTIVEMethod chaining is the pattern behind code such as counter.add(2).add(3).double().read(). Each changing method does its work, then returns this. That hands the same object to the next dot.
Each station changes the same product, then hands it to the next station. If one station forgets to hand it over, the next station has nothing to work on. That is exactly what happens when a chainable method forgets return this.
- In real life: Station 1 adds a part and passes the product on
- In JavaScript:
add(2)changes the object and returnsthis - In real life: Station 2 keeps working on the same product
- In JavaScript:
.add(3)receives the same object - In real life: The final inspector reports the result
- In JavaScript:
.read()returns the final value
Where the analogy stops: An assembly line usually has many workers. A method chain may be one object repeatedly returning itself.
Step through a chain. Watch every changing method return this so the next method has an object to call.
script
value: 0, add(amount) { this.value = this.value + amount; return this; }, double() { this.value = this.value * 2; return this; }, read() { return this.value; },}; counter.add(2).add(3).double().read();const counter = { value: 0, add(amount) { this.value = this.value + amount; return this; }, double() { this.value = this.value * 2; return this; }, read() { return this.value; },}; counter.add(2).add(3).double().read();counter
Reference error when a method forgets to return: TypeError: Cannot read properties of undefined (reading 'double')
Build a chain one method at a time. Start with add, then try double, then intentionally break it.
Chain when every call naturally continues the same idea. Do not hide complicated decisions in one long line. Clear multi-line code is better than a clever chain.
Where you’ll use this
Methods show up anywhere an object has both data and behavior: form validators, shopping carts, counters, date formatters, animation builders, and tiny state objects in UI code. The object keeps related values together, and the methods describe the actions that make sense for those values.
const headline = { text: "", word(value) { this.text = this.text + value + " "; return this; }, shout() { this.text = this.text.toUpperCase(); return this; }, read() { return this.text.trim(); },}; console.log(headline.word("methods").word("click").shout().read());The builder reads like a sentence: add a word, add another word, shout, read. The reason it works is still the same small rule: each mutating method uses this for the current object and returns this for the next call.
Common misconceptions
“A method permanently knows its object.”
No. A function value can be copied. this is chosen by the call shape, not by where the function was first stored.
“this means the object where the function was written.”
The same function can be assigned to two objects. ada.introduce() and lin.introduce() use different receivers.
“Arrow functions are shorter methods.”
They are shorter functions, but they do not have their own this. Use regular method syntax when the method reads or changes object properties.
“Callbacks keep their original object.”
Passing user.say by itself loses the method call. Wrap it as () => user.say() or learn bind later.
“Every method should return this.”
Only methods meant to keep the chain going should return this. A method such as read() should return the useful value.
Constructors use this too, but in a different call shape: new Something(). That is why Constructors & new comes next.
Practice: methods and this
5 EXERCISESAdd a describe method to the object so it prints the exact sentence in the answer checker.
const book = {
title: "Eloquent JavaScript",
describe() {
return this.title + " is on the shelf";
},
};
console.log(book.describe());const book = {
title: "Eloquent JavaScript",
describe() {
return this.title + " is on the shelf";
},
};
console.log(book.describe());describe() is a method because it is a function stored on book. Called as book.describe(), this is book, so this.title is the title string.
Predict both printed lines before you run the code.
"use strict";
function label() {
return this.name;
}
const first = { name: "first", label };
const second = { name: "second", label };
console.log(first.label());
console.log(second.label());first.label() sets this to first, so the first line is first. second.label() sets this to second, so the second line is second.
Imagine a scheduler will call callback() later. Make the callback print break time.
const timer = {
label: "break time",
announce() {
console.log(this.label);
},
};
const callback = () => timer.announce();
callback();const timer = {
label: "break time",
announce() {
console.log(this.label);
},
};
const callback = () => timer.announce();
callback();The arrow wrapper has no own this, but it does not need one. Its body runs timer.announce(), so announce receives timer as this.
Build a tiny object whose word method can be called twice in one chain.
const list = {
text: "",
word(value) {
this.text = this.text + value;
return this;
},
read() {
return this.text;
},
};
console.log(list.word("go").word("!").read());const list = {
text: "",
word(value) {
this.text = this.text + value;
return this;
},
read() {
return this.text;
},
};
console.log(list.word("go").word("!").read());The first word call returns the same list object, so the second .word("!") has an object to call. read() returns the final string instead of continuing the chain.
Rewrite the greeting as a regular method so this.name points at the object.
const user = {
name: "Rae",
greet() {
return "Hi " + this.name;
},
};
console.log(user.greet());const user = {
name: "Rae",
greet() {
return "Hi " + this.name;
},
};
console.log(user.greet());A regular shorthand method receives user when called as user.greet(). The arrow version would look for this outside the object instead.
Quiz: check your understanding
7 QUESTIONSEvery choice explains itself. For code questions, use the dot rule before you answer.
Question 1 of 7Which object is
thisinsidecat.meow()?Choose an answer to see the explanation.
Question 2 of 7What does this pet method print?
Read the code, then predictconst pet = { name: "Nori", speak() { console.log(this.name); }, }; pet.speak();Choose an answer to see the explanation.
Question 3 of 7Which syntax is method shorthand?
Choose an answer to see the explanation.
Question 4 of 7What happens in strict code when you detach a method and call it as a plain function?
Read the code, then predict"use strict"; const user = { name: "Ari", say() { console.log(this.name); }, }; const fn = user.say; fn();Choose an answer to see the explanation.
Question 5 of 7Why does
counter.add(2).double()work in a chainable API?Choose an answer to see the explanation.
Question 6 of 7What does this counter chain print?
Read the code, then predictconst counter = { value: 1, add() { this.value = this.value + 1; return this; }, read() { console.log(this.value); }, }; counter.add().add().read();Choose an answer to see the explanation.
Question 7 of 7Which callback keeps the method call shape?
Choose an answer to see the explanation.
Key takeaways
- A method is a function stored in an object property.
- Method shorthand
greet() { ... }is the common way to write regular object methods. - For
obj.method(),thisisobj, decided at call time. - Detached calls and bare callbacks lose the object before the dot; arrow wrappers or
bindcan fix that. - Chainable methods return
this; final reader methods return the useful value.
Remember the one-liner.
A method is an object’s function; this is the object before the dot for that call.
Up next: Constructors & new.