Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Deep Dive into the JavaScript new Operator and instanceof

Tech May 12 2

The Mechanism of the new Operator

In JavaScript, the new operator is used to instantiate a constructor function. While it might seem like a simple keyword, it performs a sequence of specific oeprations internally:

  1. Object Creation: A brand new empty object is created.
  2. Prototype Linking: The internal [[Prototype]] (often accessible via __proto__) of the new object is linked to the prototype property of the constructor function.
  3. Execution: The constructor function is called with this bound to the new object.
  4. Return Handling: If the constructor returns an object, that object is returned. Otherwise, the newly created object is returned.

We can simulate this behavior with a custom function:

function createInstance(Constructor, ...args) {
    // 1. Create a new object
    const instance = {};

    // 2. Link the prototype
    Object.setPrototypeOf(instance, Constructor.prototype);

    // 3. Execute the constructor with the new object as context
    const result = Constructor.apply(instance, args);

    // 4. Return the object (handling explicit object returns)
    return (result !== null && typeof result === 'object') ? result : instance;
}

Understanding instanceof

The instanceof operator checks whether the prototype property of a constructor exists anywhere in the prototype chain of an object.

Syntax: object instanceof Constructor

We can visualize its internal logic as a loop that traverses the prototype chain:

function checkInstance(object, Constructor) {
    let proto = Object.getPrototypeOf(object);
    while (proto !== null) {
        if (proto === Constructor.prototype) {
            return true;
        }
        proto = Object.getPrototypeOf(proto);
    }
    return false;
}

Practical Example: Properties and Prototypes

Consider the following example involving a constructor function:

function Gadget(brand) {
    this.brand = brand;
}

// Static property on the constructor itself
Gadget.power = "electric";

// Method on the prototype
Gadget.prototype.start = function() {
    console.log("Starting " + this.brand);
};

const phone = new Gadget("Pixel");

Let's analyze how phone accesses properties:

  • phone.brand: This property was defined on this during the constructor execution.
  • phone.power: This returns undefined. power is a static property on the Gadget function object, not on its prototype, so its not inherited by instances.
  • phone.start(): The phone object does not have a start property. JavaScript looks up the prototype chain and finds it on Gadget.prototype.

The constructor function Gadget is also an object. Its prototype chain is Gadget -> Function.prototype -> Object.prototype -> null. Therefore, Gadget.power works (static property), but Gadget.start() would fail because start is not defined on the constructor or its prototype chain.

The Impact of Prototype Assignment Timing

The behavior of instanceof depends heavily on when the prototype is assigned relative to object creation.

function Base() {}
function Child() {}

// Scenario 1: Prototype assigned before instantiation
Child.prototype = new Base();
const instanceA = new Child();

console.log(instanceA instanceof Child); // true
console.log(instanceA instanceof Base);   // true

// Scenario 2: Prototype assigned after instantiation
function Parent() {}
function Kid() {}
const instanceB = new Kid();
Kid.prototype = new Parent();

console.log(instanceB instanceof Kid);    // false
console.log(instanceB instanceof Parent); // false

In the second scenario, instanceB was created with a reference to the original Kid.prototype. Changing Kid.prototype afterwards affects future instances but not instanceB, whose internal prototype link still points to the old prototype object.

Advanced Execution Context Challenge

The following code snippet combines new, this binding, variable hoisting, and prototype chains. Analyze the execution flow:

function Processor() {
    log = function() {
        console.log(1);
    };
    return this;
}

Processor.log = function() {
    console.log(2);
};

Processor.prototype.log = function() {
    console.log(3);
};

var log = function() {
    console.log(4);
};

function log() {
    console.log(5);
}

// Execution sequence:
Processor.log();       // Output: 2
log();                  // Output: 4
Processor().log();      // Output: 1
log();                  // Output: 1
new Processor.log();    // Output: 2
new Processor().log();   // Output: 3
new new Processor().log(); // Output: 3

Execution Breakdown:

  1. Processor.log(): Calls the static method attached directly to the function object. Output: 2.
  2. log(): Variable hoisting moves the declaration var log and function declaration function log to the top. The assignment log = function(){...} (outputting 4) overwrites the function declaration. Output: 4.
  3. Processor().log(): Processor is called as a regular function. Inside, log = function(){...} assigns a new function to the global log variable (outputting 1). It returns this, which is the global object (or undefined in strict mode). Calling .log() on the global object executes the newly assigned global log. Output: 1.
  4. log(): The global log variable was modified in the previous step. Output: 1.
  5. new Processor.log(): The new operator is applied to the static method Processor.log. It executes the method (outputting 2) and returns a new instance of that function object. Output: 2.
  6. new Processor().log(): Creates a new instance of Processor. The instance inherits from Processor.prototype. The .log() method is found on the prototype. Output: 3.
  7. new new Processor().log(): Equivalent to new (new Processor().log)(). First, new Processor() creates an instance. Then, instance.log retrieves the prototype method (outputting 3). Finally, new invokes that method as a constructor. Output: 3.
Tags: javascript

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.