Understand how this changes depending on call site. Learn function borrowing, explicit binding with call, apply, and bind, and why arrow functions behave differently.
Why: this refers to different objects depending on call site. In a method it is the object, in a regular function it is undefined (strict) or globalThis, in arrow functions it is the enclosing scope.
// In a method — this is the object
const user = {
name: 'Alice',
greet() {
return `Hi, I'm ${this.name}`;
},
};
console.log(user.greet()); // "Hi, I'm Alice"
// In a regular function — this is undefined in strict mode
function showThis() {
'use strict';
return String(this);
}
console.log(showThis()); // 'undefined'
// Arrow function — inherits this from enclosing scope
const timer = {
label: 'timer',
start() {
// Regular fn here would lose 'this'
const tick = () => `${this.label} ticking`;
return tick();
},
};
console.log(timer.start()); // 'timer ticking'Why: these methods let you explicitly set what this is. call and apply invoke immediately; bind returns a new function with this locked in.
function introduce(greeting, punctuation) {
return `${greeting}, I'm ${this.name}${punctuation}`;
}
const alice = { name: 'Alice' };
const bob = { name: 'Bob' };
// call — args as comma-separated list
console.log(introduce.call(alice, 'Hello', '!'));
console.log(introduce.call(bob, 'Hey', '.'));
// apply — args as an array
console.log(introduce.apply(alice, ['Hi', '?']));
// bind — returns a new function with this locked
const aliceIntro = introduce.bind(alice, 'Howdy');
console.log(aliceIntro('!!'));
console.log(aliceIntro('...')); // reuse with different punctuation
// Function borrowing
const obj = { name: 'Charlie' };
const result = introduce.call(obj, 'Greetings', '~');
console.log(result);