Given `function Dog(name) { this.name = name; }`, what happens if you call `Dog('Rex')` without `new`, and how does the outcome differ between sloppy mode and strict mode?
answer
- capitalisation is not a mechanism
- plain call, so undefined comes back
- the mode decides what this is
- silent global versus immediate throw
- modules and class bodies are always strict
basics
~20 sWithout new, Dog runs as a plain function and returns undefined. In sloppy mode this is the global object, so name silently leaks into global state; in strict mode this is undefined and the assignment throws a TypeError immediately.
solid answer
~50 sA forgotten `new` turns construction into an ordinary call: no object is created, no prototype link is made, and the function's return value — `undefined` here — is what you get. What happens to `this.name = name` depends on the mode. In sloppy mode `this` defaults to the global object, so the assignment quietly creates or overwrites a global `name`, and the bug surfaces far away when `const d = Dog('Rex')` leaves `d` as `undefined` and `d.name` throws "Cannot read properties of undefined". In strict mode `this` stays `undefined`, so the very first assignment throws a `TypeError` at the point of the mistake, which is much easier to debug. That matters in practice because ES modules and class bodies are always strict, while a classic non-module script is sloppy. A `class` constructor is stricter still: calling it without `new` always throws.
code
javascript · 18 linesfunction Dog(name) {
this.name = name;
}
// Sloppy mode (classic script, no directive):
Dog('Rex');
console.log(globalThis.name); // 'Rex' — silently written to global state
console.log(Dog('Rex')); // undefined — nothing was constructed
// Strict mode:
(function () {
'use strict';
try {
Dog.call(undefined, 'Rex'); // same receiver a plain strict call would give
} catch (e) {
console.log(e.constructor.name); // 'TypeError'
}
})();go deeper
Know that without the keyword the function just runs and returns undefined, so the variable you assigned holds undefined and blows up the moment you touch a property on it.
Explain the mode split precisely: sloppy substitutes the global object for the receiver so the write succeeds silently, strict leaves it undefined so the assignment throws at once. Name where each mode applies.
Demonstrate the diagnosis: reason from an undefined result or a mystery global back to the call site, and say why moving the code to strict mode or a module converts a distant symptom into a local failure.
Argue the API-level fix. Decide whether the codebase should expose new-able constructors at all, and weigh factories, classes, and enforced guards against subclassability and the cost of a hardening check in every constructor you ship.
## What the call actually is `Dog('Rex')` is a plain function call. Nothing about the identifier being capitalised, or about `Dog.prototype` existing, changes that — the constructor behaviour lives entirely in the `new` operator, not in the function. So none of the construction steps happen: no object is created, no prototype link is set up, and the value of the expression is whatever the body returns. A constructor body normally returns nothing, so the expression is `undefined`. ```js function Dog(name) { this.name = name; } const d = Dog('Rex'); d; // undefined d.name; // TypeError: Cannot read properties of undefined ``` Notice where the error lands: not on the line with the mistake, but on the line that uses the result. That distance is what makes the bug annoying. ## Sloppy mode: `this` becomes the global object In non-strict ("sloppy") code, a function called with no receiver gets `this` substituted with the global object — `globalThis`. The assignment therefore succeeds, and writes a global: ```js // classic <script>, no "use strict" function Dog(name) { this.name = name; } Dog('Rex'); globalThis.name; // 'Rex' ``` Two things make this worse than a plain crash. First, state is corrupted silently: if two call sites forget `new`, the second overwrites the first, and something else reading that global name gets a value it never expected. Second, in a browser `name` is an existing property of the global object with string semantics, so the write lands somewhere real rather than in a harmless slot — the class of collision you cannot reason about locally. ## Strict mode: `this` stays `undefined` Strict mode removes the substitution. A plain call passes `undefined` as the receiver and it stays `undefined`, so the first property assignment fails immediately: ```js 'use strict'; function Dog(name) { this.name = name; } Dog('Rex'); // TypeError: Cannot set properties of undefined (setting 'name') ``` This is strictly better: the failure is loud, at the offending call, with a stack that points at the caller. It is one of the concrete reasons the mode exists. ## Which mode am I actually in? The answer changes by context, and candidates who only ever write modules often get it wrong when shown a plain script. Code inside an ES module is strict whether or not you say so. Class bodies are strict. A classic script, or a function in a CommonJS file with no directive, is sloppy unless it opts in with `'use strict'`. So the same source text can silently leak a global in one file and throw in another. ## The class case With `class Dog { constructor(name) { this.name = name; } }`, `Dog('Rex')` throws a `TypeError` saying the class constructor cannot be invoked without `new` — before any body code runs, in every mode. Classes closed this hole deliberately; it is one of the behavioural differences between a class and a constructor function, not merely a syntax difference. ## Diagnosing it in real code The symptom you usually meet first is `undefined` where an object was expected, or an instance that mysteriously fails an identity or type check. Useful moves: - Look at the assignment, not the crash site: `const x = Thing(...)` with a capitalised callee and no `new` is the tell. - In sloppy code, check for a global that appeared out of nowhere; a stray `globalThis.name`, `globalThis.id` or similar is a fingerprint of this bug. - Turn the file strict (or move it to a module) and re-run: the failure jumps from far away to the exact line. ## Preventing it Three defences, in ascending order of reliability: put the code in strict mode so the mistake fails loudly; have the function detect that it was called without construction and reject or self-correct; or use a `class`, which enforces the rule for you. A fourth option is to stop exposing a constructor at all and export a factory function that internally constructs and returns the object — then there is no `new` for a caller to forget, at the cost of giving up the constructor surface. ## Why this is asked It is a compact test of three separate pieces of knowledge at once: that `new` and not the function carries the construct behaviour, that `this` binding for a plain call differs by mode, and that a function with no `return` yields `undefined`. A candidate who can walk from the forgotten keyword to the global write to the far-away `TypeError` has a working mental model rather than a memorised rule.
- Why does the same forgotten `new` throw immediately in one file and corrupt a global in another?Because the two files differ in mode. In sloppy mode a call with no receiver substitutes the global object for `this`, so the assignment succeeds and writes a global. In strict mode no substitution happens, `this` is `undefined`, and the first property write throws. ES modules and class bodies are strict by default, classic scripts are not.
- If the value came back as `undefined`, how would you track down which call site forgot the keyword?Work backwards from the assignment rather than the crash. Find where the `undefined` was produced — a capitalised callee with no `new` is the signature — then run the file in strict mode or as a module so the failure moves to the offending line. In sloppy code, an unexpected global property with a constructor-ish name is a second fingerprint.
- Does the same trap exist for `class Dog { ... }`?No. Invoking a class constructor without `new` throws a `TypeError` before any body code runs, in every mode, because a class constructor deliberately refuses ordinary calls. That is a behavioural guarantee a plain constructor function does not give you, and it is one reason to prefer `class` for types callers construct.
saying these in an interview costs you the question
- Claims the call still returns a new object because the name is capitalised
- Says this is undefined in every mode, so it always throws
- Reports the failure as a ReferenceError rather than a TypeError
- Assumes a plain script file is strict by default
- Thinks the error appears on the line that forgot the keyword in sloppy mode