Author Watermark

Chapter 2: Arrow Functions & Implicit Returns

Prerequisites & Mental Check:

  • Chapter 1 Fundamentals: Memory allocation, Execution Context, and why assigning functions to const places them in the Temporal Dead Zone (TDZ) rather than hoisting the function body.
  • Basic Functions: Familiarity with calling and declaring standard JavaScript functions (function name() {}).
  • Basic Objects & Scope: Understanding key-value pairs ({ key: value }) and variable visibility inside blocks.

πŸ“Ί Video Explanation

Watch the full explanation of these notes here: https://youtu.be/YPpgMgaEaR4


What is Hoisting ?

Hoisting is a JavaScript mechanism where variable, function, and class declarations are moved to the top of their containing scope (global or function) during the compilation phase, before the code is executed

What is Scope ?

Scope is the current context of execution that determines the accessibility (visibility) of variables, functions, and objects in your code.


In our previous chapter we have studied that when const keyword is used, It allocates memory but keep it in a Temporal dead zone and In execution phase It can not be used before it's initilasation. But In case of function declaration: It allocates memory for the function. It creates the actual function object immediately. It binds the function name to that object in the current scope. This means the function is fully usable and initialized in memory. There fore we can use it even at the first line of code in the same scope.


Are arrow function and function expression same ?

No, arrow functions and function expressions are not exactly the same.
An arrow function is actually a special type of function expression. While they share the same scoping and hoisting rules, they have major differences under the hood regarding how they handle the this keyword, arguments, and object creation.

1. What They Have in Common

Both are expressions. This means:


2. The Core Technical Differences

Feature Regular Function Expression Arrow Function Expression
this Binding Dynamic: Defined by how the function is called. Lexical: Inherits this from the surrounding code scope.
arguments Object Yes: Has access to the local arguments array. ❌ No: Must use rest parameters (...args) instead.
Constructor (new) Yes: Can be used with new to create objects. ❌ No: Cannot be used with new (will throw a error).
Syntax Verbose (function() { return x; }) Short (() => x)


When opening any modern React Native project, one visual change immediately jumps out: traditional function keywords have almost completely disappeared, replaced everywhere by const declarations and fat arrows (=>).

Arrow functions do far more than clean up syntax. They change how expressions are returned, transform how the engine binds the this keyword in memory, and form the architectural foundation for React Native components, custom hooks, and event pipelines.


1. Syntax Evolution: Regular Functions vs. Arrow Functions

Before ES6, every function in JavaScript was created using the function keyword:

JS
function add(a, b) {
  return a + b;
}

ES6 introduced the arrow function syntax. Instead of creating a hoisted function declaration, you declare an anonymous function expression and assign it to a variable (typically const):

JS
const add = (a, b) => {
  return a + b;
};

Both snippets accomplish the exact same calculation, but arrow functions introduce a cleaner, more modular structure and unlock implicit returns.

Under the Hood (Connecting to Chapter 1):
A standard function add() {} is hoisted completely into memory during Phase 1. An arrow function const add = () => {} follows the const rules from Chapter 1: the identifier add is hoisted, but remains uninitialized in the Temporal Dead Zone (TDZ) until the assignment line runs during Phase 2.


2. Implicit Returns: Writing Expressive One-Liners

In standard JavaScript functions, you must explicitly open a block {} and write the return keyword to output a value.

With arrow functions, if your logic consists of a single expression, you can discard both the curly braces {} and the return keyword entirely. The JavaScript engine automatically evaluates that single expression and returns its value.

JS
// Form 1: Explicit return (standard block body)
const double = (n) => {
  return n * 2;
};

// Form 2: Implicit return (concise single expression)
const double = (n) => n * 2;

// Form 3: Single parameter shorthand (dropping parameter parentheses)
const double = n => n * 2;

All three forms produce identical output in memory. In React Native development, you will alternate between all three based on code complexity.

The Object Literal Gotcha: Returning {}

A very common trap occurs when you try to return an object literal implicitly.

JS
// ❌ WRONG: JavaScript thinks the {} is a function body block!
const getUser = () => { name: "Subrata" };
console.log(getUser()); // Logs: undefined

Why does this happen?

The JavaScript parser sees the curly brace { immediately after => and treats it as the start of a function body block, not an object. It tries to interpret name: "Subrata" as a label statement, finds no return keyword, and returns undefined.

JS
// βœ… CORRECT: Wrap the object literal in parentheses ()
const getUser = () => ({ name: "Subrata" });
console.log(getUser()); // Logs: { name: "Subrata" }

The outer parentheses () act as an evaluation wrapper, instructing the engine: "Evaluate the contents inside as a single expression (an object literal), not a code block."


3. Where Arrow Functions Live in React Native

Arrow functions power three core patterns in daily React Native programming:

1. Inline Event Handlers

Instead of declaring a separate named function for a one-line action, you pass an inline arrow function directly into component event props like onPress or onChangeText:

REACT
<Button onPress="{()" title="Save"> console.log("Saved!")}
/>

2. Rendering Lists with .map()

When mapping an array of data into UI elements, arrow functions with implicit returns keep your JSX concise and declarative:

REACT
const steps = [1000, 2000, 3000];

const StepList = () => (
  <View>
    {steps.map(step => (
      <Text key="{step}">{step} steps</Text>
    ))}
  </View>
);

πŸ’‘ The React Native JSX Connection:
In React Native, components return JSX markup (like <View> and <Text>). Whenever you see {} inside JSX, it tells React: "Pause markup and evaluate the JavaScript expression inside." That is why our .map() arrow function sits inside curly braces {}. Wrapping the returned JSX element in () allows you to use an implicit return across multiple lines safely.

3. Functional Component Definitions

Most functional components in modern React Native are written as arrow functions assigned to const:

REACT
// Standard component with explicit body
const HomeScreen = () => {
  return <View/>;
};

// Simple presentational component using an implicit return
const Divider = () => <View style="{styles.divider}"/>;

4. The this Difference: Dynamic vs. Lexical Scope

Topic Prerequisite: The this keyword in JavaScript refers to the execution context of the function call.

The fundamental operational difference between regular functions and arrow functions is how they handle this.

JS
Regular Function: Dynamic 'this'
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ The value of 'this' changes depending on     β”‚
β”‚ HOW and WHERE the function is called at      β”‚
β”‚ runtime(Caller-dependent).                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Arrow Function: Lexical 'this'
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Has NO 'this' of its own. It inherits        β”‚
β”‚ 'this' directly from the surrounding scope   β”‚
β”‚ where it was WRITTEN in memory.              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The Bug with Regular Functions

Because regular functions create their own dynamic this, running them inside asynchronous callbacks (like setInterval or setTimeout) causes them to lose access to the parent object:

JS
const timer = {
  seconds: 0,
  start: function () {
    setInterval(function () {
      this.seconds++; // ❌ `this` points to the global/window scope, NOT `timer`
      console.log(this.seconds); // NaN
    }, 1000);
  },
};

The Arrow Function Fix

Arrow functions do not bind their own this. They capture the surrounding lexical scope's this automatically:

JS
const timer = {
  seconds: 0,
  start: function () {
    setInterval(() => {
      this.seconds++; // βœ… `this` correctly points to the `timer` object!
      console.log(this.seconds); // 1, 2, 3...
    }, 1000);
  },
};

Note on Modern React Native: Functional components and React Hooks (useState, useEffect) eliminate the need to manage this manually in daily UI tasks. However, understanding lexical scope remains essential when working with legacy class components, third-party native libraries, and timer utilities.


5. Architectural Comparison

Feature Regular Function (function) Arrow Function (=>)
Syntax
function name() {}
const name = () => {}
Implicit Return
❌ No (requires explicit return) βœ… Yes (for single expressions)
this Binding
Dynamic (defined by caller) Lexical (inherited from outer scope)
Constructor Capability
βœ… Yes (new MyFunction()) ❌ No (cannot be used with new)
arguments Object
βœ… Available natively ❌ Unavailable (use ...args rest parameters)
React Native Usage
Rare (legacy classes/methods) Universal (components, hooks, callbacks)

The Decision Rule

JS
Do you need dynamic `this`, `arguments`, or a constructor function?
  β”œβ”€β”€ Yes β†’ Regular Function(`function`)
  └── No  β†’ Arrow Function(`=>`) (Default choice across React Native)

6. Common Pitfalls & Mistakes

Pitfall 1: Breaking Implicit Returns Across Multiple Lines

If you place a multi-line JSX expression on a new line without parentheses, JavaScript's Automatic Semicolon Insertion (ASI) inserts an invisible ; right after =>, returning undefined:

REACT
// ❌ FAILS: JavaScript returns undefined before reaching <View>
const Card = () =>
  <View>
    <Text>Hello</Text>
  </View>

// βœ… FIX: Wrap multi-line JSX in parentheses
const Card = () => (
  <View>
    <Text>Hello</Text>
  </View>
);

Pitfall 2: Recreating Function References in Render Lists

Declaring inline arrow functions directly inside loop iterators or list props allocates a brand-new function instance in memory on every single render cycle:

REACT
// ❌ SUBOPTIMAL: Re-allocates memory for every item during every render
<FlatList data="{items}" item renderItem="{({"> <ItemCard item="{item}"/>}
/>

// βœ… OPTIMIZED: Memoize the callback reference outside the render pass
const renderItem = useCallback(({ item }) => (
  <ItemCard item="{item}"/>
), []);

<FlatList data="{items}" renderItem="{renderItem}"/>

Technical Interview Questions

Q1: What will be logged to the console by the following code, and why?

JS
const user = {
  name: "Alex",
  printRegular: function() {
    console.log(this.name);
  },
  printArrow: () => {
    console.log(this.name);
  }
};

user.printRegular();
user.printArrow();

Q2: What is the output of running this function?

JS
const makeProfile = () => { id: 101, status: "Active" };
console.log(makeProfile());

Q3: Can you invoke an arrow function with the new keyword? Why or why not?


Q4: How do arrow functions handle the arguments object compared to standard functions?


Q5: Convert the following function into a concise arrow function utilizing implicit return and object wrapping:

JS
function createCoordinates(x, y) {
  return {
    latitude: x,
    longitude: y,
    timestamp: Date.now()
  };
}
JS
const createCoordinates = (x, y) => ({
  latitude: x,
  longitude: y,
  timestamp: Date.now()
});