Lesson 55: Mastering JavaScript Arrow functions with this keyword

manoj ymkmanoj ymk
6 min read

✅ What are Arrow Functions?

Arrow functions (() => {}) are a concise syntax for writing functions in JavaScript introduced in ES6. However, their behavior is not just syntactic — they differ from regular functions in several critical ways:

  • No this binding.

  • No arguments object.

  • Can’t be used as constructors.

  • No super or new.target.

✅ Syntax Examples:

// Basic Arrow Function
const add = (a, b) => a + b;

// With block body
const greet = (name) => {
  console.log(`Hello, ${name}`);
};

// Single parameter — parentheses optional
const square = x => x * x;

✅ Use Case: this binding in objects

const team = {
  name: "Developers",
  members: ["Alice", "Bob"],
  logMembers() {
    this.members.forEach(member => {
      console.log(this.name + ": " + member);
    });
  }
};
team.logMembers();
// Developers: Alice
// Developers: Bob

Visual: Lexical this binding flow

+---------------------------+
| Outer function or object  |
|     this = "Developers"   |
+------------+--------------+
             |
             v
     Arrow Function (=>) uses outer `this`

🔹 2. Fill Any Gaps

✅ Internal Mechanics

  • Arrow functions don’t create their own this, arguments, super, or new.target.

  • this is lexically bound — captured from the surrounding non-arrow function or global context.

  • They cannot be used with .call(), .apply(), .bind() to set this.

const obj = {
  value: 42,
  getValue: () => this.value
};
console.log(obj.getValue()); // undefined, because `this` is global, not `obj`

✅ Arrow Functions vs .bind(this)

function Regular() {
  this.age = 10;
  const log = function() {
    console.log(this.age); // undefined
  }.bind(this);
  log();
}

function Arrow() {
  this.age = 20;
  const log = () => console.log(this.age); // 20
  log();
}

✅ No arguments

const showArgs = () => {
  console.log(arguments); // ReferenceError!
};

Workaround: use rest parameters

const showArgs = (...args) => {
  console.log(args); // OK
};

✅ Not constructible

const A = () => {};
new A(); // TypeError: A is not a constructor

✅ Return value quirks

const foo = () => { value: 42 }; // returns undefined! Not an object!
const bar = () => ({ value: 42 }); // returns { value: 42 }

✅ Cannot be used as method shorthand

const obj = {
  sayHi: () => console.log("Hi") // works, but not recommended — `this` is wrong
};

🔹 3. Challenge Me Deeply

🟢 Basic

  1. Convert a traditional function to an arrow function while maintaining behavior.

  2. Create an arrow function that returns an object literal.

  3. Write an arrow function that takes rest parameters and logs the sum.

  4. Show what this refers to in an arrow function inside a method.

🟡 Intermediate

  1. Create an object method that logs internal state using both regular and arrow functions — explain the difference.

  2. Implement a higher-order function that delays execution using arrow functions.

  3. Create a custom map function that works like Array.prototype.map using arrow functions internally.

🔴 Advanced

  1. Simulate partial application using arrow functions and closures.

  2. Write a function that tracks how many times it's been called — use arrow functions but preserve access to the enclosing this.

  3. Write a decorator function that modifies behavior of an arrow function while preserving the lexical this.

🎯 Brain-Twister

  1. What will be logged and why?
const obj = {
  count: 0,
  inc: () => {
    this.count++;
    console.log(this.count);
  }
};
obj.inc();

🔹 4. Interview-Ready Questions

✅ Conceptual

  • How does this behave differently in arrow functions vs regular functions?

  • Why can’t arrow functions be used as constructors?

  • Can you overwrite the this of an arrow function using .bind()?

✅ Scenario-Based

  • You’re inside a React class component method and want to bind a callback to this. Do you use arrow functions or .bind()? Why?

  • You notice a callback in an event listener doesn't have access to expected object state. What could be wrong?

✅ Debugging Challenge

function Timer() {
  this.seconds = 0;
  setInterval(function () {
    this.seconds++;
    console.log(this.seconds);
  }, 1000);
}
new Timer(); // Output? Fix it.

✅ Best Practices

✅ Use arrows for short callbacks and closures.
❌ Don’t use arrows for object methods if you need this.
✅ Prefer arrows in React component class callbacks or functional components.
❌ Avoid arrow functions where dynamic this is required (e.g., event handlers in DOM manipulation libraries like jQuery).


🔹 5. Real-World Usage

✅ Frontend

  • React: Common for event handlers, map callbacks, and memoized selectors.

  • Redux: Arrow functions in reducers, thunks, selectors.

  • Event Listeners: Often used when inner function needs lexical this.

jsCopyEditbutton.addEventListener('click', () => this.doSomething());

✅ Backend (Node.js)

  • In async patterns with setTimeout, fs.readFile, or promise chains.
fs.readFile('file.txt', (err, data) => {
  if (!err) console.log(data.toString());
});

✅ Libraries

  • Lodash/Underscore use internally for function utilities.

  • RxJS pipelines benefit from arrow syntax for concise transformation chains.


🔹 6. Remember Like a Pro

✅ Mnemonics

"Arrow shoots this from the outer scope."

  • A-R-R-O-W =
    Always
    Refer
    to outer
    Runtime
    Over
    Window scope

✅ Cheatsheet

FeatureArrow FunctionRegular Function
thisLexicalDynamic
arguments❌ No✅ Yes
super❌ No✅ Yes
new operator❌ Not allowed✅ Allowed
Used as method⚠ Avoid✅ Yes

🔹 7. Apply It in a Fun Way

🚀 Mini Project: Custom Delayed Button

A button that shows a message after a delay, using closures + arrow functions to preserve context.

✅ Steps:

  1. Create a button in HTML: <button id="delayed">Click me</button>

  2. Write a JS function setupDelay(buttonId, delay, message)

  3. Inside it, use setTimeout with arrow function to show alert

  4. Use this context captured from setup function (log it)

function setupDelay(buttonId, delay, message) {
  const button = document.getElementById(buttonId);
  button.addEventListener('click', function () {
    setTimeout(() => {
      alert(message);
      console.log("Context is:", this); // captured from outer scope
    }, delay);
  });
}

setupDelay("delayed", 2000, "Hello after 2 seconds!");

➕ Bonus Extension

  • Allow custom styling after delay

  • Log delay countdown using setInterval and arrow functions


🧠 Bonus: Power Tips, Mistakes, and Polyfills

❌ Common Mistakes

  • Assuming this behaves the same as regular functions.

  • Using arrow functions as methods:

const obj = {
  val: 42,
  getVal: () => this.val // ❌ undefined
};
  • Returning objects without parentheses.
const f = () => { value: 42 }; // ❌ undefined

✅ Performance Tips

  • Arrow functions are slightly faster for inline operations due to smaller scope creation.

  • Ideal for short-lived callbacks and chained transformations.

  • Avoid using in memory-critical recursion or hot loops.

❗ Polyfill?

Arrow functions can't be polyfilled in ES5 — their behavior depends on lexical scoping and this binding at parse time. Babel transpiles them to regular functions with manual binding where possible.

0
Subscribe to my newsletter

Read articles from manoj ymk directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

manoj ymk
manoj ymk