JavaScript Object Methods: A Complete Tutorial
Master JavaScript object methods from basic definitions to advanced patterns. Learn how to define methods, use shorthand syntax, understand this binding, chain methods, and work with built-in Object methods with practical examples.
A method is a function stored as a property of an object. Methods give objects behavior: a user object can have a greet() method, a calculator can have add() and subtract(), and a shoppingCart can have addItem() and getTotal(). Understanding how methods work, how this binds inside them, and how to use built-in Object utility methods are essential skills for every JavaScript developer.
This tutorial covers defining methods, shorthand syntax, this binding rules, method chaining, and the most important built-in Object methods you will use daily.
Defining Object Methods
Function Expression (Classic Syntax)
The traditional way to add a method is assigning a function expression to a property:
const user = {
name: "Alice",
age: 28,
greet: function() {
return `Hi, I'm ${this.name}`;
},
getAge: function() {
return `I'm ${this.age} years old`;
}
};
console.log(user.greet()); // "Hi, I'm Alice"
console.log(user.getAge()); // "I'm 28 years old"Method Shorthand (ES6)
ES6 introduced a shorter syntax that removes the : function part. This is the preferred modern style:
const user = {
name: "Alice",
age: 28,
greet() {
return `Hi, I'm ${this.name}`;
},
getAge() {
return `I'm ${this.age} years old`;
}
};
console.log(user.greet()); // "Hi, I'm Alice"
console.log(user.getAge()); // "I'm 28 years old"Method Shorthand vs Function Expression
| Feature | Shorthand greet() {} | Expression greet: function() {} |
|---|---|---|
| Syntax length | Shorter | Longer |
this binding | Same (dynamic) | Same (dynamic) |
| Can be a constructor | No | Yes |
super keyword access | Yes | No |
| Preferred in modern JS | Yes | Legacy |
Adding Methods After Creation
You can add methods to an existing object at any time:
const calculator = {
value: 0
};
calculator.add = function(n) {
this.value += n;
return this;
};
calculator.subtract = function(n) {
this.value -= n;
return this;
};
calculator.reset = function() {
this.value = 0;
return this;
};
calculator.add(10).subtract(3).add(5);
console.log(calculator.value); // 12Understanding this in Methods
The this keyword inside a method refers to the object that called the method. It is not determined by where the method is defined, but by how it is called:
const user = {
name: "Alice",
greet() {
return `Hi, I'm ${this.name}`;
}
};
console.log(user.greet()); // "Hi, I'm Alice"
// `this` depends on the CALLER
const greetFn = user.greet;
console.log(greetFn()); // "Hi, I'm undefined" (or error in strict mode)Why Arrow Functions Break this
Arrow functions do not have their own this. They inherit this from the enclosing scope, which makes them unsuitable as object methods:
const user = {
name: "Alice",
// WRONG: arrow function inherits outer `this` (window/undefined)
greetArrow: () => {
return `Hi, I'm ${this.name}`; // `this` is NOT user
},
// CORRECT: regular method has dynamic `this`
greetMethod() {
return `Hi, I'm ${this.name}`; // `this` is user
}
};
console.log(user.greetArrow()); // "Hi, I'm undefined"
console.log(user.greetMethod()); // "Hi, I'm Alice"Arrow Functions Inside Methods (Valid Use)
Arrow functions are useful inside methods when you need to preserve the method's this in nested callbacks:
const team = {
name: "Engineering",
members: ["Alice", "Bob", "Charlie"],
listMembers() {
// Arrow function inherits `this` from listMembers
return this.members.map(member => {
return `${member} - ${this.name} team`;
});
}
};
console.log(team.listMembers());
// ["Alice - Engineering team", "Bob - Engineering team", "Charlie - Engineering team"]Method Chaining
Method chaining lets you call multiple methods in sequence by returning this from each method:
class TaskManager {
constructor() {
this.tasks = [];
this.filter = "all";
}
addTask(title, priority = "medium") {
this.tasks.push({ title, priority, done: false });
return this; // Enable chaining
}
completeTask(title) {
const task = this.tasks.find(t => t.title === title);
if (task) task.done = true;
return this;
}
setFilter(filter) {
this.filter = filter;
return this;
}
getFilteredTasks() {
if (this.filter === "done") return this.tasks.filter(t => t.done);
if (this.filter === "pending") return this.tasks.filter(t => !t.done);
return this.tasks;
}
summary() {
const total = this.tasks.length;
const done = this.tasks.filter(t => t.done).length;
return `${done}/${total} tasks completed`;
}
}
const manager = new TaskManager()
.addTask("Design UI", "high")
.addTask("Write tests", "medium")
.addTask("Deploy app", "high")
.completeTask("Design UI")
.setFilter("pending");
console.log(manager.getFilteredTasks());
// [{ title: "Write tests", ... }, { title: "Deploy app", ... }]
console.log(manager.summary()); // "1/3 tasks completed"Built-in Object Methods
JavaScript's built-in Object class provides utility methods for inspecting and transforming objects.
Object.keys()
Returns an array of an object's own enumerable property names:
const user = {
name: "Alice",
age: 28,
email: "alice@example.com"
};
console.log(Object.keys(user));
// ["name", "age", "email"]Object.values()
Returns an array of an object's own enumerable property values:
const scores = {
math: 92,
science: 88,
english: 95
};
console.log(Object.values(scores));
// [92, 88, 95]
// Useful for calculations
const average = Object.values(scores).reduce((sum, s) => sum + s, 0) / Object.keys(scores).length;
console.log(average); // 91.67Object.entries()
Returns an array of [key, value] pairs, perfect for iteration:
const product = {
name: "Laptop",
price: 999,
brand: "TechBrand"
};
for (const [key, value] of Object.entries(product)) {
console.log(`${key}: ${value}`);
}
// name: Laptop
// price: 999
// brand: TechBrand
// Transform to Map
const productMap = new Map(Object.entries(product));
console.log(productMap.get("price")); // 999Object.fromEntries()
The reverse of Object.entries(). Converts an array of [key, value] pairs back into an object:
const entries = [
["name", "Alice"],
["age", 28],
["role", "developer"]
];
const user = Object.fromEntries(entries);
console.log(user); // { name: "Alice", age: 28, role: "developer" }
// Useful with Map
const priceMap = new Map([
["apple", 1.50],
["banana", 0.75],
["orange", 2.00]
]);
const priceObj = Object.fromEntries(priceMap);
console.log(priceObj); // { apple: 1.5, banana: 0.75, orange: 2 }Object.assign()
Copies properties from source objects into a target object:
const defaults = { theme: "light", fontSize: 14, lang: "en" };
const userPrefs = { theme: "dark", fontSize: 18 };
const settings = Object.assign({}, defaults, userPrefs);
console.log(settings);
// { theme: "dark", fontSize: 18, lang: "en" }Summary of Built-in Methods
| Method | Returns | Purpose |
|---|---|---|
Object.keys(obj) | string[] | Get all own enumerable property names |
Object.values(obj) | any[] | Get all own enumerable property values |
Object.entries(obj) | [string, any][] | Get all own enumerable [key, value] pairs |
Object.fromEntries(arr) | object | Create an object from [key, value] pairs |
Object.assign(target, ...sources) | object | Copy properties from sources into target |
Object.freeze(obj) | object | Prevent all property changes |
Object.seal(obj) | object | Prevent adding/deleting, allow updates |
Object.getPrototypeOf(obj) | `object | null` |
Practical Example: Form Validator
Here is a real-world example combining multiple method patterns:
const FormValidator = {
rules: {},
addRule(field, validator, message) {
if (!this.rules[field]) this.rules[field] = [];
this.rules[field].push({ validator, message });
return this;
},
required(field, message) {
return this.addRule(field, value => value !== "" && value != null, message || `${field} is required`);
},
minLength(field, min, message) {
return this.addRule(field, value => String(value).length >= min, message || `${field} must be at least ${min} characters`);
},
isEmail(field, message) {
return this.addRule(field, value => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value), message || `${field} must be a valid email`);
},
validate(data) {
const errors = {};
for (const [field, rules] of Object.entries(this.rules)) {
for (const rule of rules) {
if (!rule.validator(data[field])) {
if (!errors[field]) errors[field] = [];
errors[field].push(rule.message);
}
}
}
return {
valid: Object.keys(errors).length === 0,
errors
};
},
reset() {
this.rules = {};
return this;
}
};
FormValidator
.required("name")
.minLength("name", 2, "Name must be at least 2 characters")
.required("email")
.isEmail("email");
const result = FormValidator.validate({
name: "A",
email: "invalid"
});
console.log(result);
// { valid: false, errors: { name: ["Name must be at least 2 characters"], email: ["email must be a valid email"] } }Best Practices
- Use method shorthand (
greet() {}) as the default for defining methods on object literals - Never use arrow functions as top-level object methods; they break
thisbinding - Return
thisfrom setter methods to enable chaining - Prefer
Object.keys/values/entriesoverfor...inloops because they skip inherited properties automatically - Keep methods focused: each method should do one thing and have a descriptive name
Common Mistakes to Avoid
Losing this When Extracting Methods
const counter = {
count: 0,
increment() {
this.count++;
}
};
// WRONG: extracting loses `this`
const inc = counter.increment;
inc(); // `this` is undefined in strict mode
// CORRECT: bind the method
const boundInc = counter.increment.bind(counter);
boundInc(); // Works: this.count becomes 1Rune AI
Key Insights
- Method shorthand: Use
greet() {}overgreet: function() {}in object literals for cleaner syntax - this binding:
thisinside a method refers to the object that called it, not where it was defined - Arrow functions: Never use as top-level object methods; they inherit outer
thisand break method behavior - Method chaining: Return
thisfrom methods to enable fluentobj.a().b().c()call chains - Built-in methods:
Object.keys,Object.values, andObject.entriesconvert objects to arrays for iteration
Frequently Asked Questions
What is the difference between a function and a method?
Can I use [default parameters](/tutorials/programming-languages/javascript/how-to-use-default-parameters-in-js-functions) in object methods?
Should I use Object.keys or for...in to iterate objects?
Why does `this` change when I pass a method as a callback?
What are getter and setter methods?
Conclusion
Object methods combine data and behavior in a single structure. Shorthand method syntax keeps definitions clean, this binding tells the method which object it operates on, and method chaining creates fluent APIs. The built-in Object.keys, Object.values, and Object.entries methods transform objects into arrays for easy iteration and transformation. Mastering these patterns gives you the foundation for working with JavaScript's object-oriented features and building well-organized, maintainable code.
More in this topic
OffscreenCanvas API in JS for UI Performance
Master the OffscreenCanvas API to offload rendering from the main thread. Covers worker-based 2D and WebGL rendering, animation loops inside workers, bitmap transfer, double buffering, chart rendering pipelines, image processing, and performance measurement strategies.
Advanced Web Workers for High Performance JS
Master Web Workers for truly parallel JavaScript execution. Covers dedicated and shared workers, structured cloning, transferable objects, SharedArrayBuffer with Atomics, worker pools, task scheduling, Comlink RPC patterns, module workers, and performance profiling strategies.
JavaScript Macros and Abstract Code Generation
Master JavaScript code generation techniques for compile-time and runtime metaprogramming. Covers AST manipulation, Babel plugin authorship, tagged template literals as macros, code generation pipelines, source-to-source transformation, compile-time evaluation, and safe eval alternatives.