Menu
CoddyTech

JavaScript this, Prototypes and Classes Interview Questions

How this is bound, how the prototype chain works, and what classes add.

10 questions
  1. How does this work in JavaScript?

    this is decided by how a function is called, not where it is defined. By priority:

    1. new Fn(): the new object.
    2. call, apply or bind: the object passed.
    3. obj.fn(): obj.
    4. a plain fn(): undefined in strict mode, the global object otherwise.

    Arrow functions skip all four and use the surrounding this.

    JavaScript
    'use strict';
    function who() {
      return this?.name;
    }
    const user = { name: 'Ada', who };
    class Person {
      constructor(name) {
        this.name = name;
      }
    }
    console.log(user.who(), who(), who.call({ name: 'Grace' }), new Person('Linus').name);

    More in the this keyword.

  2. What is the difference between call, apply and bind?

    All three set this. call and apply invoke at once, with arguments listed or as an array; bind returns a new function with this and any given arguments fixed.

    JavaScript
    'use strict';
    function introduce(greeting, punct) {
      return `${greeting}, I am ${this.name}${punct}`;
    }
    const ada = { name: 'Ada' };
    console.log(introduce.call(ada, 'Hi', '.'));
    console.log(introduce.apply(ada, ['Hello', '.']));
    const bound = introduce.bind(ada, 'Hey');
    console.log(bound('?'));

    Use bind to pass a method as a callback without losing its object.

  3. What happens to this when you copy a method out of its object?

    JavaScript
    'use strict';
    const user = {
      name: 'Ada',
      getName() {
        return this?.name;
      },
    };
    const getName = user.getName;
    console.log(user.getName(), getName(), getName.call(user));

    this is set at call time. The copied getName() is a plain call, so in strict mode this is undefined; call(user) sets it back. Passing user.getName as a callback hits the same bug; fix it with bind.

  4. What is the prototype chain?

    Every object links to a prototype, another object or null. A property the object lacks is looked up along that chain until null, which is how inheritance works.

    JavaScript
    const animal = {
      eats: true,
      describe() {
        return `${this.name} eats: ${this.eats}`;
      },
    };
    const dog = Object.create(animal);
    dog.name = 'Rex';
    console.log(dog.describe());
    console.log(Object.getPrototypeOf(dog) === animal, Object.hasOwn(dog, 'eats'));
    console.log(Object.getPrototypeOf(Object.prototype));

    Reads go up the chain; an assignment creates an own property unless the chain holds a setter or read-only property of that name. See prototypes.

  5. What is the difference between __proto__ and prototype?

    prototype is a property of constructors and classes: what instances made with new inherit from. __proto__ is an accessor on Object.prototype that exposes an object's actual prototype, so in browsers and Node.js instance.__proto__ === Constructor.prototype.

    JavaScript
    function User(name) {
      this.name = name;
    }
    const u = new User('Ada');
    console.log(Object.getPrototypeOf(u) === User.prototype, User.prototype.constructor === User);
    console.log(typeof User.prototype, u.prototype);

    __proto__ is deprecated; use Object.getPrototypeOf and Object.setPrototypeOf.

  6. Are JavaScript classes different from constructor functions?

    Mostly no: a class is syntax over constructor functions and prototypes, and typeof a class is 'function'. The differences are that class bodies are strict, methods are non-enumerable, classes need new, and declarations sit in the temporal dead zone.

    JavaScript
    class Shape {
      constructor(name) {
        this.name = name;
      }
      area() {
        return 0;
      }
      toString() {
        return `${this.name} with area ${this.area()}`;
      }
    }
    class Circle extends Shape {
      constructor(r) {
        super('circle');
        this.r = r;
      }
      area() {
        return Math.round(Math.PI * this.r ** 2);
      }
    }
    console.log(String(new Circle(2)));
    console.log(typeof Shape, Object.getPrototypeOf(Circle.prototype) === Shape.prototype);

    In a subclass, call super() before touching this.

  7. What does the new keyword do? Can you implement it?

    new Fn(args) creates an empty object, sets its prototype to Fn.prototype, calls Fn with this bound to it, and returns it, unless Fn returns an object of its own.

    JavaScript
    function myNew(Ctor, ...args) {
      const obj = Object.create(Ctor.prototype);
      const result = Ctor.apply(obj, args);
      return result !== null && (typeof result === 'object' || typeof result === 'function')
        ? result
        : obj;
    }
    function User(name) {
      this.name = name;
    }
    User.prototype.greet = function () {
      return 'hi ' + this.name;
    };
    const u = myNew(User, 'Ada');
    console.log(u.greet(), u instanceof User);

    Get the last step right: a returned primitive is ignored, a returned object replaces the instance.

  8. How do you make private properties in JavaScript?

    Use private fields, written with #. Only code inside the class body can reach them; outside access is a syntax error.

    JavaScript
    class Account {
      #balance = 0;
      deposit(n) {
        this.#balance += n;
        return this;
      }
      get balance() {
        return this.#balance;
      }
    }
    const acc = new Account().deposit(100);
    console.log(acc.balance, Object.keys(acc).length, '#balance' in acc);

    The field is invisible to Object.keys, JSON.stringify and a string in check, so this prints 100 0 false.

  9. What is the difference between const and Object.freeze?

    const stops the variable from being reassigned; Object.freeze makes the object itself read-only, one level deep.

    JavaScript
    'use strict';
    const config = Object.freeze({ port: 3000, db: { host: 'localhost' } });
    try {
      config.port = 8080;
    } catch (e) {
      console.log(e.constructor.name);
    }
    config.db.host = 'remote';
    console.log(config.port, config.db.host, Object.isFrozen(config.db));

    Writing to a frozen property throws in strict mode and is ignored otherwise, and config.db is still writable.

  10. How does instanceof work in JavaScript? Can you implement it?

    obj instanceof Ctor walks obj's prototype chain and is true if it meets Ctor.prototype. It checks the chain, not how the object was built.

    JavaScript
    function myInstanceOf(obj, Ctor) {
      if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) return false;
      let proto = Object.getPrototypeOf(obj);
      while (proto !== null) {
        if (proto === Ctor.prototype) return true;
        proto = Object.getPrototypeOf(proto);
      }
      return false;
    }
    
    class Animal {}
    class Dog extends Animal {}
    const rex = new Dog();
    console.log(myInstanceOf(rex, Animal), rex instanceof Animal);
    console.log(myInstanceOf('hi', String), 'hi' instanceof String);
    console.log(Object.create(null) instanceof Object, Array.isArray([]));

    Primitives are never instances, and an array made in another frame (an iframe) fails instanceof Array, so use Array.isArray. A class can override the check with static [Symbol.hasInstance].

Coddy programming languages illustration

Learn to code with Coddy

Get started