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
thiscontext determined at invocation time, support theargumentsobject, and can serve as constructors withnew. - Arrow functions inherit
thislexically from their parent scope, lack their ownargumentsobject, and cannot be used as constructors or rebound withcall/apply/bind. - The
lydiahallie/javascript-questionsrepository highlights these differences inREADME.mdlines 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →