assigning values to properties in constructor function - javascript

I am working on an assignment for a JS course.
Instructions say to:
setHrs() function takes input of hours worked. function should save input to its instance variable name hrs. no returns.
Okay, so I am pretty much stuck. Below is my code, where I define the employees, give them properties, share those properties between Employee --> Employee1 --> Employee2
Once I got Employees sorted out, I need to create functions within Hourly() that I can then call on later in the program; getRate() and getHrs().
I need pointers for assigning new values to this.rate and this.hrs, here is my code:
//Prince of Wales, Bed and Breakfast Resort
function Employee(id, name, hiredate, position){
this.id = id;
this. name = name;
this.hiredate = hiredate;
this.position = position;
}
Employee.prototype.hired = "Employed";
var Employee1 = new Employee("4", "Blackadder",
"06-03-1902", "butler");
var Employee2 = new Employee("5", "Baldrick",
Employee1.hiredate, "who knows");
// printed out to test prototype works... everything above can be printed
function Hourly(rate, hrs) {
this.rate = 0;
this.hrs = 0;
this.setHrs = function(){
// set Employee1 hours
// set Employee2 hours
}
this.setRate = function() {
// set Employee1 rate
// set Employee2 rate
}
}
Hourly.prototype = new Employee();
Employee1.prototype.hrs = 50;
Employee2.prototype.hrs = 25;
Employee1.prototype.rate = 4;
Employee2.prototype.rate = 1;
console.log(
"Name : " , Employee1.name ,
" Hourly Rate : ", Employee1.setRate(),
" Hours Worked : ", Employee1.setHrs(),
);
console.log(
"Name : " , Employee2.name ,
" Hourly Rate : ", Employee2.setRate(),
" Hours Worked : ", Employee2.setHrs(),
);
I had thought of something else that might work, it doesn't, but I might be on the right track???
this.setHrs = function(){
Employee1.hrs = 50;
Employee2.hrs = 25;
}
this.setRate = function() {
Employee1.rate = 4;
Employee2.rate = 1;
}
I have also thought, maybe rate and hrs should be arrays and I can push values to them, but everything I tried didn't add values to the arrays. Plus, if I do that then when I print the array, I could end up with more problems.
SOLUTION EDIT:
function Employee(id, name){
this.id = id;
this. name = name;
} // end of employee()
function Hourly(id, name) {
Employee.call(this,id,name);
var rate = 0.0;
var hrs = 0.0;
this.setHrs = function(time){ this.hrs = time; }
this.setRate = function(pay) { this.rate = pay; }
My main issue may have been the variable set up. I thought I understood prototypal inheritance, but there were some small details that caused my code not to run. once I changed my code from
this.rate = rate;
this.hrs = hrs;
to
var rate = 0;
var hrs = 0;
it was pretty much smooth sailing from there. Additionally, I needed to call the previous function Employee(). My employee variables are defined later in the code, but they are pretty much set up the same except for one important change... calling the appropriate function.
var Employee1 = new Hourly("2262124", "Blackadder");
Employee1.setHrs(50);
Employee1.setRate(4);
Employee1.getPayCheck();
console.log(" ");
previously, I called Employee() and that worked for assigning values to name and id, but not for setting rate and hrs which are "further" down in the inheritance chain. I then passed ALL properties to the Hourly() function and my properties were getting their values appropriately.
I just wanted to post my solution here for others who may be having issues practicing with inheritance. Thank you for reading and commenting!!

The setter functions need to take a parameter, and then they should update the property of the current object.
this.setHrs = function(hours){
this.hrs = hours;
}
You shouldn't be accessing Employee1 and Employee2 inside the methods, because the caller can have other variables containing these objects. They use those variables when they call the method:
Employee1.setHrs(50);
Employee2.setHrs(25);

Part of the problem was also the , instead of + in console.log
function Employee(id, name, hiredate, position){
this.id = id;
this. name = name;
this.hiredate = hiredate;
this.position = position;
this.rate = 0;
this.hours = 0;
}
Employee.prototype.hired = "Employed";
Employee.prototype.setHrs =function(hours){
this.hours = hours;
}
Employee.prototype.setRates = function(rates){
this.rate = rates;
}
function Hourly (employeeContext,hours, rates){
employeeContext.setRates(rates);
employeeContext.setHrs(hours);
}
var Employee1 = new Employee("4", "Blackadder",
"06-03-1902", "butler");
var Employee2 = new Employee("5", "Baldrick",
Employee1.hiredate, "who knows");
//calling Hourly
Hourly(Employee1, 4, 25);
Hourly(Employee2, 1, 50);
console.log(
"Name : " + Employee1.name +
" Hourly Rate : " + Employee1.rate+
" Hours Worked : "+ Employee1.hours
);
console.log(
"Name : " + Employee2.name +
" Hourly Rate : "+ Employee2.rate+
" Hours Worked : "+ Employee2.hours
);

setHrs() function takes input of hours worked
You should be passing some parameters to this function. A setter function will take some input and "set" some object variable.
setHrs(hours)
You should do this for each Employee object you create.
Employee1.setHrs(50)
Employee2.setHrs(25)
I hope this helped.
EDIT
For clarification on what I meant:
If you were to create an Employee object like you already have
function Employee(id, name, hiredate, position){
this.id = id;
this.name = name;
this.hiredate = hiredate;
this.position = position;
}
Then you can instantiate Employees like this:
var johnSmith = new Employee("6", "John Smith", "04-28-2017", "Chef")
Now if we were to modify the Employee class like this:
function Employee(id, name, hiredate, position){
this.id = id;
this.name = name;
this.hiredate = hiredate;
this.position = position;
this.setHrs = function (hours) = {
this.hours = hours;
}
this.setRate = function (rate) = {
this.rate = rate;
}
}
Now you are able to instantiate the Employee object like I did above but now you can call these member functions on the object.
johnSmith.setHours(50);
johnSmith.setRate(25);
There are ways to handle inheritance if you had to handle both salary and hourly workers, but this solution will work if you only have to deal with hourly workers.

Related

When I call a method with setInterval, it diesn't give back a number [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 months ago.
I created a Car (Auto in German) class to simulate the speed of a Car. I want the Ford object to start at 0 and increase its speed every second by 15. For this, I used setInterval. But, when I call the plus() function in setInterval, it gives me back NaN every second.
When I just call the method by using Ford.plus();, It works perfectly and gives back an Integer
//require "prompt-sync"
const prompt = require("prompt-sync")({ sigint: true });
//Auto class
class Car{
constructor(brand, speed, maxSpeed, currentSpeed){
this.carBrand = brand;
this.carSpeed = speed;
this.carMaxSpeed = maxSpeed;
this.carCurrentSpeed = currentSpeed;
}
drive(){
if(this.carCurrentSpeed >= this.carMaxSpeed){
clearInterval(inter);
console.log("too fast");
}else{
this.carCurrentSpeed = this.carCurrentSpeed + this.carSpeed;
console.log(this.carBrand + " has a speed of " + this.carCurrentSpeed + " km/h");
}
}
}
//gameloop
for(var i = 0; i < 3; i++){
//infos from usr
let brand = prompt("what brand is your car? ");
let speed = parseInt(prompt("How much speed does your car gain per second? "));
let maxSpeed = parseInt(prompt("what is the maximum speed of your car? "));
//create Object
var usrAuto = new Car(brand, speed, maxSpeed, 0);
let inter =setInterval(function() {
usrAuto.drive.call(usrAuto)
}, 1000);
}
The bind function binds an object to a function to be used as this for that function. It returns the function itself, having that object bound to it.
setInterval( Ford.plus.bind(Ford), 1000 )
Personally, I don't like this new function introduced in a recent JavaScript version. Instead I would have:
setInterval(function() {
Ford.plus.call(Ford)
}, 1000)

Can I create two object instances that contain different methods

I completely understand the concept of prototype inheritance in JavaScript if the methods in the constructor are the same for all instances. But what if I want to create objects via constructors but want the methods to produce a different result for each instance?
function Player (health, power, stamina) {
this.health = health;
this.power = power;
this.stamina = stamina;
this.recovery = function () {
return this.health += 20;
}
}
var hulk = new Person ( 100,80,60 );
var superman = new Person ( 100,70,50);
My problem here is I want hulks recovery to add 20 when I call the recovery method but I want superman’s to add 40. If I add the method to the prototype instead of directly into the object I still want that method to be only for the hulk and a different one for superman. Do I create object literals for this and specify the different methods for each object? This seems long wielded if I had hundreds of characters! Or do I add another multiple methods to the Person prototype even if it’s only going to be used by one instance? What’s the best way to make superman’s recovery better than the hulks whilst still using a constructor ? Thanks all.
Pass a 4th parameter to Player, one which indicates health regen:
function Player(health, power, stamina, healthRegen) {
this.health = health;
this.power = power;
this.stamina = stamina;
this.healthRegen = healthRegen;
this.recovery = function() {
return this.health += this.healthRegen;
}
}
var hulk = new Person(100, 80, 60, 20);
var superman = new Person(100, 70, 50, 40);
If most characters had a particular amount of health regen (say, 20), and you only wanted superman and a couple others to have different health regen, you could use a default parameter to avoid having to write 20 so much:
function Player(health, power, stamina, healthRegen = 20) {
this.health = health;
this.power = power;
this.stamina = stamina;
this.healthRegen = healthRegen;
this.recovery = function() {
return this.health += this.healthRegen;
}
}
var hulk = new Person(100, 80, 60);
var superman = new Person(100, 70, 50, 40);
var normalPerson = new Person(50, 50 50);
Above, see how you only need to pass the 4th parameter when the desired health regen is other than 20; otherwise, it'll default to 20.

Moving all class variables to "this"

Here's part of my code:
class Light {
constructor(xpos,zpos,ypos,range,diffuser,diffuseg,digguseb,intensity,angle,exponent) {
this.xpos = xpos;
this.ypos = ypos;
this.zpos = zpos;
this.range = range;
this.diffuser = diffuser;
this.diffuseg = diffuseg;
this.diffuseb = diffuseb;
this.intensity = intensity;
this.angle = angle;
this.exponent;
[...]
Is there any way to move all given argument variables to this so I can access them later?
var lt = new Light(0,12,15,...);
alert(lt.zpos); //outputs '12'
I'm looking for a solution to put those 11 this lines to one
This does what you desire. The portion in mapArgsToThis which gets the argument names was taken from here. mapArgsToThis would be a helper function you would use when you want to be lazy.
var mapArgsToThis = function(func, args, thisPointer) {
var argsStr = func.toString().match(/function\s.*?\(([^)]*)\)/)[1];
var argNames = argsStr.split(',').map(function(arg) {
return arg.replace(/\/\*.*\*\//, '').trim();
}).filter(function(arg) {
return arg;
});
var argValues = Array.prototype.slice.call(args);
argNames.forEach(function(argName, index) {
thisPointer[argName] = argValues[index];
});
};
var MyConstructor = function(xpos,zpos,ypos,range,diffuser,diffuseg,digguseb,intensity,angle,exponent) {
mapArgsToThis(MyConstructor, arguments, this);
};
var myInstance = new MyConstructor(1,2,3,4,5,6,7,8,9,0);
console.log(myInstance);
Even though this is a solution, I don't recommend it. Typing out the argument mapping to your this properties is good for your fingers and is easier for others to read and know what's going on. It also doesn't allow for any processing of the argument values prior to assignment onto this.

How to create a constructor function?

Problem: I'm trying to create a constructor function named Wizard that takes 2 parameters: name and spells, and then create a Wizard object:
"Each particular instance of wizard must have a name property (a string), a spells property which is an array of strings, and a castSpell method capable of returning a random spell in string format."
The object has the following properties: name is "Gorrok" (string), and spells is "abracadabra" and "cadabraabra" (array).
Objective: to invoke the castSpell method to display a random spell like so:
Gorrok : abracadabra
Code: I've only written the following code so far, and I'm stuck at this stage!
function Wizard(name, spells){
this.name = name;
this.spells = [spells];
this.castSpell = function(){
var v = Math.random();
if (v >= 1)
document.write(this.name + " : " + this.spells[0]);
else
document.write(this.name + " : " + this.spells[1]);
}
}
var w = new Wizard("Gorrok", "abracadabra", "cadabraabra");
w.castSpell();
So, Math.random() will return a number between 0 and 1, so it'll never be bigger than 1.
Also, you can't convert the remaining arguments to an array the way you have.
Simplest fix:
function Wizard(name, spells){
this.name = name;
this.spells = spells; // assume spells is already an array
this.castSpell = function(){
var v = Math.random();
if (v >= 0.5)
document.write(this.name + " : " + this.spells[0]);
else
document.write(this.name + " : " + this.spells[1]);
}
}
var w = new Wizard("Gorrok", ["abracadabra", "cadabraabra"]);
w.castSpell();
I think Paul's answer is correct. Also, for functions not in ctor, use prototype. Prototypes also allow you add member vars that are not defined in constructor.
Here's an example from w3:
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
Person.prototype.nationality = "English";
You can also use Math.round() to get 0 or 1 randomly
var v = Math.round( Math.random() );
document.write(this.name + " : " + this.spells[v]);

How to call on an objects property value outside of the object maker

I am trying to make an equation for player damage that uses the monsters defense as a calculation. Since each monster has a different defense value I do not know how to code it to change based on the selected monster. Here is what I tried.
JSFiddle
var playerGold = 0;
var playerExp = 0;
var playerLvl = 1;
var expNeeded = 10;
var playerHP = 10;
var playerATK = 1;
var playerDEF = 1;
var playerSPD = 1;
function Monster(name, exp, gold, hp, atk, def, spd) {
this.name = name;
this.exp = exp;
this.gold = gold;
this.hp = hp;
this.atk = atk;
this.def = def;
this.spd = spd;
// Method definition
this.implement = function() {
var monsterList = document.getElementById('monsterList');
var opt = document.createElement('OPTION'); // Creating option
opt.innerText = this.name; // Setting innertText attribute
monsterList.appendChild(opt); // appending option to select element
}
var playerDam = function () {
var playerDamage = Math.round(playerATK - this.def);
}
// Method execution
this.implement();
}
var fly = new Monster("fly", 1, 1, 5, 1, 0, 1);
var mouse = new Monster("mouse", 2, 3, 10, 2, 0, 2);
var rat = new Monster("rat", 4, 5, 20, 4, 2, 2);
var rabidChihuahua = new Monster("rabid chihuahua", 6, 8, 35, 6, 1, 4);
var bulldog = new Monster("bulldog", 10, 14, 60, 10, 4, 1);
$('#battleButton').click(function() {
playerDam();
$('#dam').html("You have hit the " + $('#monsterList').val() + " for " + playerDamage + " damage");
});
One way to achieve what you want, is to :
- save a reference to this in the Monster class (as self for example)
- save a reference to each Monster object in a data attribute of the option element.
function Monster(name, exp, gold, hp, atk, def, spd) {
var self = this;
/* ...*/
this.implement = function() {
/* ... */
// we save the Monster object (self) in the
// <option></option> data attribute 'monster'
$(opt).data('monster', self)
}
// and your playerDam function becomes:
this.playerDam = function () {
self.playerDamage = Math.round(playerATK - this.def);
return self.playerDamage;
}
}
When the user click the button, you retrieve the current selected value, and get the data attribute :
monsterEl = $('#monsterList option:selected');
// we retrieve the monster selected from the <option></option> data attribute
monster = monsterEl.data('monster')
$('#dam')
.html("You have hit the " + $('#monsterList').val() + " for " + monster.playerDam() + " damage");
See the updated fiddle
Edit
You have a list of monsters, if you just do:
var opt = document.createElement('OPTION'); // Creating option
opt.innerText = this.name;
Then you don't save the monster, but just the monster's name.
So you have to keep a reference to the monster object in each option element.
One way to do this is to use data-attributes whose purpose are to store an object with a name (here I chose monster but it could be any string), that you could retrieve later.
When you create a new monster like var fly = new Monster("fly", 1, 1, 5, 1, 0, 1), this will create an <option data-monster="you monster object"></option> element (the data-monster will not show in the source, but trust me, it's there), containing the Monster object with all its properties (name, hp, exp...).
When you click the button, jQuery will get the selected option and retrieve the data with the key monster:
// get the selected option via CSS selector
monsterEl = $('#monsterList option:selected')
// get the associated Monster via the .data('monster') method
monster = monsterEl.data('monster')
// now you can invoke method on the monster variable
console.log(monster.name ) // 'fly'
console.log(monster.hp ) // 5
Now as for the playerDam() function :
var self = this
this.playerDamage = 0;
this.playerDam = function () {
self.playerDamage = Math.round(playerATK - self.def);
return self.playerDamage;
}
You are assigning the playerDam function to the Monster function scope (this).
To access the Monster scope inside the function, you have to use a trick and use a variable (here self, but could be any variable name) to store the Monster scope beforehand. Then you can access it from inside the playerDam function.
You could also have used a method on the prototype to save up memory:
Monster.prototype.playerDam = function() {
// 'this' is the now the Monster class scope
this.playerDamage = Math.round(playerATK - this.def);
return this.playerDamage;
}
I hope I was clear, this mix a lot of different concepts together, maybe other could explain it better that I did ;)
You should take a look at Javascript framework such as Knockout , react, or vue.js which make this easier for you!
Edit 2
I've reupdated the fiddle to fix this.def in the playerDam function

Categories

Resources