Function and Arrow Function Scope in JavaScript: 4 Critical Differences Explained

Regular functions create their own dynamic this context at invocation time, while arrow functions inherit this lexically from their parent scope and cannot be rebound.

Understanding the distinction between function and arrow function scope is essential for avoiding common JavaScript pitfalls. According to the lydiahallie/javascript-questions repository—a widely-used resource for JavaScript interview preparation—these scope differences primarily manifest in how this binding, the arguments object, and constructor behavior are handled.

How Function and Arrow Function Scope Differ

Lexical vs. Dynamic this Binding

The most significant difference lies in this resolution. Regular functions establish this based on the invocation context—whether called as a method, constructor, or with call/apply/bind. Arrow functions capture this from their enclosing lexical environment at definition time.

As documented in README.md lines 141-145 of the repository: "With arrow functions, the this keyword refers to its current surrounding scope, unlike regular functions! This means that when we call perimeter, it doesn't refer to the shape object, but to its surrounding scope."

The arguments Object Availability

Regular functions possess their own arguments object containing passed parameters. Arrow functions lack this object entirely, inheriting arguments from the outer scope if it exists, or throwing a ReferenceError if accessed directly.

Constructor and Prototype Limitations

Regular functions can serve as constructors when invoked with new, possessing an internal [[Construct]] method and a prototype property. Arrow functions cannot be used as constructors—attempting to call them with new throws a TypeError—and they do not have a prototype property.

Practical Code Examples

Object Method Context from README.md

The repository provides a concrete demonstration of scope differences in object methods:

const shape = {
  radius: 10,
  // Regular function: `this` refers to `shape` when called as `shape.diameter()`
  diameter() {
    return this.radius * 2;          // → 20
  },
  // Arrow function: `this` is taken from the surrounding (global) scope
  perimeter: () => 2 * Math.PI * this.radius,
};

console.log(shape.diameter());  // 20
console.log(shape.perimeter()); // NaN (because `this.radius` is undefined)

Attempting to Rebind this

Arrow functions ignore bind, call, and apply attempts:

function Person(name) {
  this.name = name;
}

// Regular function can be rebound
const greet = function () {
  return `Hi, I'm ${this.name}`;
};
const boundGreet = greet.bind({ name: 'Alice' });
console.log(boundGreet()); // Hi, I'm Alice

// Arrow function ignores bind()
const arrowGreet = () => `Hi, I'm ${this.name}`;
const boundArrow = arrowGreet.bind({ name: 'Bob' });
console.log(boundArrow()); // Hi, I'm undefined (uses global `this`)

Constructor Usage

Demonstrating the instantiation limitation:

function Car() { 
  this.wheels = 4; 
}
const myCar = new Car(); // Works fine

const ArrowCar = () => { 
  this.wheels = 4; 
};
// const myArrowCar = new ArrowCar(); 
// TypeError: ArrowCar is not a constructor

Summary

  • Regular functions create their own this context determined at invocation time, support the arguments object, and can serve as constructors with new.
  • Arrow functions inherit this lexically from their parent scope, lack their own arguments object, and cannot be used as constructors or rebound with call/apply/bind.
  • The lydiahallie/javascript-questions repository highlights these differences in README.md lines 141-145, demonstrating how arrow functions in object literals capture the global scope instead of the object context.

Frequently Asked Questions

Can you change the this value of an arrow function using bind, call, or apply?

No. Arrow functions capture this lexically from their surrounding scope at the time they are defined. Even if you attempt to use Function.prototype.bind(), call(), or apply(), the arrow function will continue to reference its original lexical this value.

Why does an arrow function method return NaN or undefined when accessing object properties?

When an arrow function is defined as a method inside an object literal, it does not receive its own this binding. Instead, it inherits this from the enclosing scope—typically the global object (window in browsers) or undefined in strict mode. Since this.radius refers to the global scope rather than the object, the property returns undefined, causing mathematical operations to return NaN.

Do arrow functions have an arguments object like regular functions?

No, arrow functions do not have their own arguments object. If you reference arguments inside an arrow function, it will look up the scope chain to find an arguments binding in an enclosing regular function, or throw a ReferenceError if none exists. To access function parameters in an arrow function, use rest parameters (...args) instead.

Can arrow functions be used as constructors with the new keyword?

No, arrow functions cannot be used as constructors. They lack the internal [[Construct]] method required for constructor behavior, and they do not have a prototype property. Attempting to invoke an arrow function with new will throw a TypeError indicating that the function is not a constructor.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →