skip to Main Content

I’ve been taken a bunch of JavaScript riddles lately and got really stuck on this one for like a day and a half (for context, all the others took 1 hour max). Since I want to come up with the final solution myself, I will post a somewhat similar piece of code just so I can grab the general idea and implement it as per the context of the riddle.

Assume this is the piece of code:

class Vehicle {
  constructor(brand, model, power) {
    this.brand = brand;
    this.model = model;
    this.power = power;
  }

  info() {
    return `This vehicle is a ${this.brand} - ${this.model}, with a power of ${this.power}`;
  }
}


//do something with my class here such that
//the next calls will return/display as follows

const v = new Vehicle('Mercedes', 'C class', 12345);
console.log(v.info()); // This vehicle is a Mercedes - C class, with a power of 12345

const {
  info
} = v;
console.log(info()); // This vehicle is a Mercedes - C class, with a power of 12345



//To keep in mind, the function should stay the same, so a call to (info === v.info) should return true;
//And only the part of the code where it says to enter the code can be changed, so the class should be untouched.

I’m aware this shouldn’t be a case where maybe it will be used in everyday life, as it is a riddle and just meant to challenge our brain, but it challenged me to the point I give up haha.

I tried looping over the entries of the Vehicle.prototype, and setting each one that is a function and is not the constructor to the same function bound to the class, or to the class.prototype or anything similar and it doesn’t work.

How can I go about solving it, or at least make it so I can edit a function call for every time a new instance of that class is created?

Edit:
I tried using the bind method, even tried something like this

Vehicle.prototype['info'] = Vehicle.prototype['info'].bind(Vehicle.prototype);

Vehicle.prototype['info'] = Vehicle.prototype['info'].bind(Vehicle);

Vehicle.prototype['info'] = Vehicle.prototype['info'].bind(Vehicle.prototype['info']);

I tried many alternatives and they didn’t work since I have to have it bound to each instance of the class created. So if a new instance was created, and the same was done there, each one would return data according to the instance it was extracted from.

3

Answers


  1. To keep info === v.info as true. You need to use bind().

    class Vehicle {
      constructor(brand, model, power) {
        this.brand = brand;
        this.model = model;
        this.power = power;
      }
    
      info() {
        return `This vehicle is a ${this.brand} - ${this.model}, with a power of ${this.power}`;
      }
    }
    
    const v = new Vehicle('Mercedes', 'C class', 12345);
    console.log(v.info());
    
    const info = v.info;
    console.log(info.bind(v)());
    
    console.log(info === v.info);

    Update:

    Another elegant solution by gog. I added it here since this question is closed.

    class Vehicle {
        constructor(brand, model, power) {
            this.brand = brand;
            this.model = model;
            this.power = power;
        }
    
        info() {
            return `This vehicle is a ${this.brand} - ${this.model}, with a power of ${this.power}`;
        }
    }
    
    
    let fn = Vehicle.prototype.info
    Object.defineProperty(Vehicle.prototype, 'info', {
        get() {
            return this._bound ?? (this._bound = fn.bind(this))
        }
    });
    
    const v = new Vehicle('Mercedes', 'C class', 12345);
    console.log(v.info());
    
    const {
        info
    } = v;
    
    console.log(info());
    
    console.log(info === v.info)
    Login or Signup to reply.
  2. The bind() method should be used in the constructor of the class, not on the prototype.

    If you want to bind a method to the class itself, not the instance, you can do it like this:

    class Vehicle {
     static info() {
       return `This is a vehicle`;
     }
    }
    
    Vehicle.info = Vehicle.info.bind(Vehicle);
    
    console.log(Vehicle.info()); // This is a vehicle
    

    In this case, Vehicle.info = Vehicle.info.bind(Vehicle); binds the info method to the Vehicle class itself.

    Login or Signup to reply.
  3. The issue you are facing is because when you destructure info from v instance, you are basically borrowing its method so this is no longer bound properly and you need to re-bind it.

    class Vehicle {
      constructor(brand, model, power) {
        this.brand = brand;
        this.model = model;
        this.power = power;
      }
    
      info() {
        return `This vehicle is a ${this.brand} - ${this.model}, with a power of ${this.power}`;
      }
    }
    
    
    //do something with my class here such that
    //the next calls will return/display as follows
    
    const v = new Vehicle('Mercedes', 'C class', 12345);
    console.log(v.info()); // This vehicle is a Mercedes - C class, with a power of 12345
    
    // here is where the issue starts,
    // now info is no longer "connected" to v instance,
    // the function is just borrowed from that object
    const {
      info
    } = v;
    // so you need to rebind it before use
    console.log(info.bind(v)()); // This vehicle is a Mercedes - C class, with a power of 12345
    
    
    
    //To keep in mind, the function should stay the same, so a call to (info === v.info) should return true;
    //And only the part of the code where it says to enter the code can be changed, so the class should be untouched.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search