Wassim Tahraoui
Wassim Tahraoui

Reputation: 179

Node.js/Javascript - Object.setPrototypeOf() not working properly

I have a Player class that has some properties like name, id, score etc... and few methods that modify the score property
Over the course of the execution i end up saving few instances of this class to JSON files. Then later on, I import them back into an array called players. In order to retrieve the class' methods in each object in the array, I did the following:

class Player {
    constructor(_name,_id) {
        this.name = _name;
        this.age = _age;
        this.score = 0;
    }
    addScore(x) {this.score += x}
    multiplyScore(x) {this.score *= x}
    removeScore(x) {this.score -= x}

}
// The function `loadFiles()` returns: [{name:"foo",id:0,score:15},{name:"bar",id:1,score:9}]
const players = loadFiles().map(x => Object.setPrototypeOf(x, Player.prototype));

Normally, when I use the setPrototypeOf() method, it would return an instance of the class I chose with properties values from the targeted object, and then if I do console.log(players[0].constructor.name) it should print out Player except that the objects in players remain exactly the same, the methods aren't added into them and their constructor.name is not Player.
PS: the process works fine if I do this on one object instead of mapping/looping through an array of them.

Upvotes: 0

Views: 168

Answers (2)

Utkarsh Dixit
Utkarsh Dixit

Reputation: 4275

There is nothing wrong with the code, it is working completely fine.

class Player {
    constructor(_name,_id) {
        this.name = _name;
        this.age = _age;
        this.score = 0;
    }
    addScore(x) {this.score += x}
    multiplyScore(x) {this.score *= x}
    removeScore(x) {this.score -= x}

}
// The function `loadFiles()` returns: [{name:"foo",id:0,score:15},{name:"bar",id:1,score:9}]
const loadFilesResponse = [{name:"foo",id:0,score:15},{name:"bar",id:1,score:9}];
const players = loadFilesResponse.map(x => Object.setPrototypeOf(x, Player.prototype));
console.log("Score before add: ", players[0].score);
players[0].addScore(3);
console.log("Score after add: ", players[0].score);

It's possible that loadFiles doesn't actually returns the expected Object, for example it could be returning a list of promises (a common mistake when dealing with promises).

Upvotes: 3

You have the data, just create objects from that data instead of doing object prototype hackery?

const players = loadFiles().map(p => {
  const { name, age, score } = p;
  p = new Player(name, age);
  p.score = score;
  return p;
});

Although extending that constructor a little would make it less work:

class Player {
  constructor(name, age, score = 0) {
    this.name = name;
    this.age = age;
    this.score = score;
  }
  ...
}

...

const players = loadFiles().map(p => {
  const { name, age, score } = p;
  return = new Player(name, age, score);
});

This you can call the constructor with two or three arguments, and if you call it with two the score argument will simply default to 0. Much easier.

Upvotes: 1

Related Questions