this in Regular Functions
Introduction
Regular functions get their this from how they are called. They do not capture this from where they are written. That single sentence explains most interview puzzles around plain functions, callbacks, constructors, and method borrowing.
A regular function can use all four binding rules: default, implicit, explicit, and new.
Why This Matters
Regular functions are still everywhere: object methods, prototype methods, class methods under the hood, constructors, event callbacks, and utility functions. If you can predict this for a regular function, arrow functions and bind become much easier to reason about.
Theory
Regular function this is dynamic
A regular function's this is resolved when the function is invoked, not when it is defined. The same function can see different receivers across calls.
Default binding
A plain call, fn(), uses default binding. In sloppy mode, this is substituted with the global object. In strict mode, this remains undefined. Most interview explanations should prefer strict mode because it exposes the bug clearly.
Implicit binding
A property call, obj.fn(), sets this to obj. If the method is later extracted, this binding is gone.
Explicit binding
call, apply, and bind let you provide the receiver yourself. They are useful for method borrowing, callback repair, and partial application.
new binding
When a regular function is called with new, JavaScript creates a fresh object, assigns it as this, links it to the function's prototype, and returns it unless the constructor explicitly returns another object.
Constructor return rule
If a constructor returns a primitive, JavaScript ignores it and returns the new object. If it returns an object, that object replaces the new instance. This is a common advanced follow-up.
Visual Diagrams
function show() { ... }
show() -> default binding
profile.show() -> implicit binding
show.call(profile) -> explicit binding
new ShowConstructor() -> new bindingRegular functions are flexible because `this` is call-site driven.
Code Examples
The same function can have different this values
This is why you cannot inspect only the function definition to know this.
Constructor functions use new binding
Before class, constructor functions relied on new to provide the instance as this.
Playground
Press Run to execute the code and see output here.
Output Prediction
Predict the output #1
1function show() {2 'use strict';3 console.log(this === undefined ? 'plain' : this.name);4}5 6const user = { name: 'Ada', show: show };7const fn = user.show;8 9user.show();10fn();11show.call({ name: 'Grace' });Predict the output #2
1function User(name) {2 this.name = name;3 return 'ignored';4}5 6const user = new User('Ada');7console.log(user.name);8console.log(user instanceof User);Coding Exercises
Build a safe method invoker
MediumImplement invoke(object, methodName, args) so it calls object[methodName] with object as this and returns the method's result. Use it to avoid losing this when methods are selected dynamically.
Interview Questions
1How is `this` determined in a regular function?
For a regular function, this is determined by the call site. A plain call uses default binding, a property call uses implicit binding, call / apply / bind use explicit binding, and new creates a new receiver object. Strict mode changes plain-call default binding so this remains undefined.
2What happens if a constructor function returns a value?
If it returns a primitive, the return value is ignored and the newly-created object is returned. If it returns an object or function, that object replaces the newly-created instance. This only matters when the function is called with new.
Follow-ups
- How does this differ from factory functions?
- What does `new` do step by step?
Quiz
1. A regular function is called as `fn()`. In strict mode, what is `this`?
2. Which call uses implicit binding?
Summary
- Regular functions have dynamic `this`; it is decided at invocation time.
- Plain calls use default binding; strict mode makes default `this` `undefined`.
- Property calls use implicit binding.
- `call`, `apply`, and `bind` use explicit binding.
- `new` creates a fresh receiver object and has the highest precedence.
Cheat Sheet
Regular function: this comes from the call site.
Plain call: strict undefined, sloppy global object.
Property call: receiver object.
Explicit call: supplied receiver.
Constructor call: fresh object. Primitive constructor returns are ignored; object returns replace the instance.