JavaScript’s hoisting, objects, this, and new describe different parts of how code runs: when declarations become usable, how properties are found, how a function gets its receiver, and how a constructor creates an instance. They are easier to predict when you trace each mechanism separately instead of imagining that JavaScript moves code or gives every function a permanent object context.
How JavaScript objects and properties work
An object is a collection of properties keyed by strings or symbols. A property can hold a value, another object, or a function. Use dot notation when the property name is known directly, and bracket notation when it is computed or stored in a variable:
const phone = { brand: "Example", model: "A1" };
phone.model; // "A1"
phone["brand"]; // "Example"
phone.model = "A2"; // updates this object's property
A function stored in an object property is commonly called a method. That label describes how the function is used; it does not permanently bind the function to the object where it was first stored.
Own properties and the prototype chain
When JavaScript looks up a property, it first checks the object itself. If the property is not an own property, lookup can continue through the object’s prototype chain. An instance can therefore use shared behavior provided by its prototype, while holding its own data.
#1 Best Overall
For example, a property added to Car.prototype can be found by instances created from Car. By contrast, assigning car1.color adds or changes a property on that particular instance; it does not add an own property to other cars. An own property with the same name can shadow an inherited property. Not every object inherits from Object.prototype: objects can be created with a null prototype.
MDN’s Working with objects guide explains object properties and lookup, and its reference for the new operator demonstrates constructor prototypes and instance properties.
What hoisting means—and what it does not mean
“Hoisting” is a convenient metaphor for the fact that some declarations can be used before their textual position executes. It is not literal source-code movement. MDN notes that “Hoisting is not a term normatively defined in the ECMAScript specification.” The useful questions are: does a binding exist in this scope, has it been initialized, and what value can be read here?
var is initialized to undefined
A var binding is available within its function or global scope before the assignment runs. Reading it early produces undefined; the assignment still happens at its original position:
Recommended Free Tools
Rank #2
console.log(a); // undefined
var a = 1;
let and const have a temporal dead zone
Lexical declarations using let and const are in scope before their declaration is reached, but they cannot be accessed until initialization. Accessing one early throws a ReferenceError; this interval is called the temporal dead zone.
console.log(b); // ReferenceError
let b = 1;
This is a separate example: the exception stops execution of that script at the failing line. Class declarations also cannot be accessed before initialization. Imports have early availability semantics, but their rules differ from the local variable examples here.
Function declarations can be called earlier in their scope
A function declaration is available earlier in its scope, so code can call it before the declaration’s textual position:
sayHi(); // "Hi"
function sayHi() {
console.log("Hi");
}
Do not assume all declarations behave alike. The practical distinction is whether the binding is initialized and usable at the point where the code runs.
How a regular function gets its this
For regular functions, this depends on how the function is invoked, not on where it was defined. MDN summarizes it this way: “The value of this in JavaScript depends on how a function is invoked (runtime binding), not how it is defined.”
The call site supplies the receiver
In phone.describe(), the expression before the dot supplies phone as the receiver for that call. Extracting the function removes that call form, so a later standalone call does not retain the original object:
"use strict";
const phone = {
model: "A1",
describe() { return this.model; }
};
phone.describe(); // "A1"
const describe = phone.describe;
describe(); // TypeError when it tries to read model from undefined
In strict mode, a standalone regular-function call has this === undefined. In non-strict mode, a standalone call with an undefined or null receiver substitutes globalThis. The example uses strict mode so its result is explicit.
Explicit binding with call, apply, and bind
call and apply invoke a regular function immediately with a chosen receiver; apply takes arguments as an array-like value. bind returns a new function whose receiver is fixed:
Rank #4
function label(prefix) {
return prefix + this.model;
}
label.call(phone, "Phone: "); // "Phone: A1"
label.apply(phone, ["Phone: "]);
const phoneLabel = label.bind(phone);
phoneLabel("Phone: "); // "Phone: A1"
Callback APIs choose how callbacks are invoked. Passing a method as a callback does not by itself preserve the object receiver; use an arrow callback when lexical this is intended, or bind the function explicitly where appropriate.
Arrow functions inherit this
An arrow function does not create its own this. It captures the value from its surrounding lexical scope, and call, apply, or bind cannot replace that captured value. This makes arrows useful inside callbacks that need the enclosing method’s receiver, but generally unsuitable as object methods when the receiver should be chosen by the call site.
const counter = {
count: 0,
start() {
setTimeout(() => {
this.count += 1; // this is inherited from start's call
}, 0);
}
};
An object literal does not create a new this scope. Also, top-level this depends on the environment: in a browser classic script it is generally globalThis (the window object), while at the top level of a module it is undefined. Node.js CommonJS wraps module code, so its top-level behavior differs.
What the new operator does
new creates an instance and invokes a constructor with that instance as this. In practical terms, JavaScript creates an object, links it to the constructor’s prototype when that value is an object, calls the constructor with the new object as its receiver, and returns the new object unless the constructor explicitly returns a different non-primitive object.
Best Value
Trace construction step by step
- Create a new object.
- Set its prototype link from the constructor’s
prototype, if that property is an object. - Call the constructor with the new object as
this, so assignments such asthis.model = modelinitialize the instance. - Return the explicitly returned non-primitive object, if there is one; otherwise return the object created for the construction.
function Car(model) {
this.model = model;
}
Car.prototype.describe = function () {
return this.model;
};
const car1 = new Car("A1");
car1.describe(); // "A1"
car1 has its own model property and can find describe through its prototype chain. This is how construction and prototype-based property lookup fit together.
Constructor return values and classes
If a constructor returns a different non-primitive object, that object becomes the result of the new expression. Returning a primitive does not replace the instance created by new.
Class constructors must be called with new; calling a class as an ordinary function throws a TypeError. Ordinary constructor functions can be called without new, but then no instance is created and this follows ordinary function-call rules. The new.target value can be used to detect whether a function was invoked as a constructor. Not every callable value can be constructed: arrow functions are not constructors, and some built-ins are callable or constructible only in particular ways. See MDN’s new operator reference for the operator’s behavior.
Quick Recap
A quick way to predict the result
- Declaration: identify the declaration type and scope; check whether its binding has been initialized at this point.
- Property: check the object’s own properties first, then follow its prototype chain.
- Regular-function
this: inspect the call syntax. A receiver before the dot, an explicit binding method, or a standalone call gives different results. - Arrow-function
this: look outward to the lexical scope where the arrow was created. new: track the created object, its prototype link, constructor initialization, and any returned object.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →




