class UserProfile { constructor(name) { this.name = name; this.friends = []; } addFriend(friend) { this.friends.push(friend); } render() { return { name: this.name, friendCount: this.friends.length, listFriends() { return this.friends.map(friend => friend.name).join(', '); } }; } } const user = new UserProfile('Tyler'); user.addFriend({ name: 'Lynn' }); user.addFriend({ name: 'Ben' }); const profileData = user.render(); console.log(`${profileData.name} has ${profileData.friendCount} friends.`); console.log(`Friends: ${profileData.listFriends()}`);
The bug is in the listFriends method inside the render method.
render() { return { name: this.name, friendCount: this.friends.length, listFriends() { return this.friends.map(friend => friend.name).join(', '); } }; }
When listFriends is called, this no longer refers to the UserProfile instance, but instead to the object returned by render. This object doesn’t have a friends property, so this.friends is undefined. To fix this, you could use an arrow function to preserve the correct this context:
render() { return { name: this.name, friendCount: this.friends.length, listFriends: () => { return this.friends.map(friend => friend.name).join(', '); } }; }
or if you’re a sicko, you could use .bind.
render() { return { name: this.name, friendCount: this.friends.length, listFriends: function() { return this.friends.map(friend => friend.name).join(', '); }.bind(this) }; }
If you want a more detailed explanation, check out Understanding the “this” keyword, call, apply, and bind in JavaScript.