简体   繁体   中英

JS. properties in prototype weird behaviour

I'm trying to understand how to make properties work with prototype in a nodejs backed webgame.

Reasoning: Instead of doing something like: Player.attributes.pow.value It would be so much easier to read when it's: Player.pow Note: I do not want to use a function because Player.pow() makes you feel like it's doing more than just return a value.

So to test how it works I did a quick mockup and noticed an odd behaviour and although it works not sure if I should be doing this:

function Player() {
    this.attributes = { 
    pow: {
      base: 3, 
      value: 3, 
      attChanges: [], 
      multiplier: 0,
      calculateValue: function() {
        var multiplier = this.multiplier;
        var value = 0;
        this.attChanges.forEach( function(att) {
          value += att.value; // For some reason this.value returns NaN in the forEach, this is a way around that...
          multiplier += att.multiplier; 
        });
        this.value = this.base + value;
        this.value *= (1 + multiplier / 100);
      }
    }
  }
  //Change a attribute and calculate it's value
  this.attributes.pow.attChanges.push({value: 3, multiplier: 0});
  this.attributes.pow.calculateValue();
}

Player.prototype.sayHello = function() {
  console.log("hello");
}

Player.prototype = {
    get pow() {
    return this.attributes.pow.value;
    }
}

var p = new Player();

p.sayHello(); // Error
console.log(p.pow);
console.log(p.pow);
p.sayHello();

It says TypeError: p.sayHello is not a function

But if I put it below defining the property, it works

Player.prototype = {
    get pow() {
    return this.attributes.pow.value;
    }
}

Player.prototype.sayHello = function() {
  console.log("hello");
}

var p = new Player();

p.sayHello(); // hello 
console.log(p.pow); // 6
console.log(p.pow); // 6
p.sayHello(); // hello

What's going on here? Is this a bad way of doing it? I saw an example of this here: JS defineProperty and prototype It is the second answer at the moment.

When you assign the prototype for the pow instance variable, you are erasing the previous definition for the prototype to which the sayHello method is attached, so when you switch the declarations, the assignment happens first and then you add the instance method to the new prototype so everything works as expected.

If you want to define a property with a get method without redefining the entire prototype object, try something like this:

Object.defineProperty(Player.prototype, "pow", {
  get: function() {
    return this.attributes.pow.value;
  }
});

You may then place that declaration in any order relative to the sayHello declaration without worrying about unexpected side-effects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM