0

I have a Equipment parent class which takes in args and two children Weapon and Armor which also take args. I'm not sure if there is a special way to target prototypes or if my code actually isn't working but here is a shortened DEMO

I need to create the variables used for the arguments in each object based on the value of other variables as well as an algorithm that uses a random number. Each item is unique so I need to make the hp for equipment at the same time as the damage for weapons and I'm not sure how to do that.

function Equipment(hp) {
  var self = this;
  this.hp = hp;
}
//create subclass for weapons
function Weapon(baseDam) {
  var self = this;
  this.baseDam = baseDam;
}

function generateEquipment() {
  hp = Math.round(Math.random() * 10);
  baseDam = Math.round(Math.random() * 50);
  Weapon.prototype = new Equipment(hp);
  weapon = new Weapon(baseDam);
  stringed = JSON.stringify(weapon);
  alert(stringed);
}

generateEquipment();
4
  • could you please say a bit more about what you actually want to achieve? Commented Apr 29, 2016 at 13:15
  • I edited my question, hope that clarifies Commented Apr 29, 2016 at 13:34
  • Getting closer :) I don't understand why you return a "Weapon" if the method is called "generateEquipment". Are you planing to create other "Equipments" in this function? Commented Apr 29, 2016 at 13:43
  • @lipp yes in the game every time the store is visited it will generate 6 pieces of equipment with random variables. There will be about a 35% chance of it being a weapon otherwise it will be armor. Commented Apr 29, 2016 at 13:45

2 Answers 2

1

First, the answer to your question : Your code is not really wrong, and your weapon still has its hp, except that its contained in the objects prototype, so won't show when stringified. There are ways to get around this, like I've shown here, but this according to me is not the correct way to do it.

Normally, prototypes should only store methods and not instance variables, because if you later decide to modify the prototype, the instance variable will get modified as well ,in case it is passed by reference.

A better pattern would be to use Object.assign - it is the easiest to understand and feels most natural. Further, if you expect Weapon to be a subclass of equipment, that logic should be encapsulated in Weapon itself.

Here is the proposed new way of declaring your Weapon Class :

function Weapon(baseDam) {
  var self = this;
  var hp = Math.round(Math.random() * 10);
  Object.assign(self, Equipment.prototype, new Equipment(hp));
  this.baseDam = baseDam;
}

Since hp is also generated randomly, that logic is now encapsulated in Weapon. This is also scalable, as this pattern will work for long inheritence chains as well.

Some people may recommend ES6 classes, which is also an approach that would work, but in my opinion it is syntactical sugar, which hides most of the inner workings of your code.

Here is a working demo with my approach.

Sign up to request clarification or add additional context in comments.

4 Comments

This is certainly a working answer, my only problem with this is that in my actual code, their are around ten or more variables for Equipment and I don't want to have to repeat that code in function Weapon and function Armor, also this all needs to go through localStorage and I can't pass a function in localStorage
You would just have to take all the common variables and put them in the parent class... all the weapon specific and armour specific variables would go into their respective constructors see here. As for localStorage, im guessing you want to store the instances and not the constructors, so localStorage.weapon1 = new Weapon(12); would work just fine.
if I'm understanding this correctly I just need to create the variables in Weapon and Armor instead of in the generateEquipment function?
yes exactly... all instance variables should be inside the constructors as this.something = "something"
0

The 'pattern' you're describing is called 'Composition' and can be very powerful. There're many different ways of combining/composing new classes or objects.

Reading your question and comments, it seems to me that you're mainly interested in defining many different types of equipment without too much (repeated) code.

Have you thought about passing an array of class names to your generateEquipment method and returning a new, custom constructor? Here's an example:

function Equipment(hp) {
  this.hp = Math.round(hp);
}

Equipment.prototype.describe = function() {
  return "This piece of equipment has " + this.hp + " hitpoints";
}

function Weapon(baseDam) {
  this.baseDam = Math.round(baseDam);
}

Weapon.prototype.describe = function() {
  return "The weapon does " + this.baseDam + " damage";
}

function generateCustomEquipment(types) {
  var CustomEquipment = function() {
    var self = this;

    // Create the properties for all types
    types.forEach(function(type) {
      type.call(self, Math.random() * 100);
    });
  };

  CustomEquipment.prototype.describe = function() {
    var self = this;

    // Combine the 'describe' methods of all composed types
    return types
      .map(function(type) {
        return type.prototype.describe.call(self);
      })
      .join(". ");
  }

  return CustomEquipment;
}

var Sword = generateCustomEquipment([Equipment, Weapon]);
var Armor = generateCustomEquipment([Equipment]);
var Arrow = generateCustomEquipment([Weapon]);

var sword1 = new Sword();
document.writeln("A sword: " + sword1.describe() + "<br/>");

var armor1 = new Armor();
document.writeln("A piece of armor: " + armor1.describe() + "<br/>");

var arrow1 = new Arrow();
document.writeln("An arrow: " + arrow1.describe() + "<br/>");

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.