I want to create an instance of the object Player, which as an instance of the object Weapon nested in it.
For example, player1 should start the game with a dagger.
I tried different things but the nested object (weapon) is not in the player instance.
function Weapon(name, damage) {
this.name = name;
this.damage = damage;
}
function Player(name, life) {
this.name = name;
this.life = life;
this.weapon = {
name: name,
damage: damage
};
}
const player1 = new Player("Joueur 1", 100, dagger);
const dagger = new Weapon("Dague", 5);
const sword = new Weapon("Epée", 10);
const axe = new Weapon("Hache", 15);
const flail = new Weapon("Fléau", 20);
What is the right syntax to add this weapon as a nested object?
Also, the weapon may change during the game.
I think you're looking for something like this, you're currently trying to pass a parameter but the constructor isn't expecting it. I've given 2 examples of how you could achieve this.
function Weapon(name, damage) {
this.name = name;
this.damage = damage;
}
function Player(name, life, weapon) {
this.name = name;
this.life = life;
this.weapon = weapon;
}
const dagger = new Weapon("Dague", 5);
const player1 = new Player("Joueur 1", 100, dagger);
const player2 = new Player("Joueur 1", 100, new Weapon("Dague", 5));
console.log(player1);
console.log(player2);
Related
const Player = (name, mark) => {
let markedSpots = [];
const markSpot = (spot) => {
markedSpots.push(spot);
};
const clearSpots = () => {
markedSpots = [];
};
return {name, mark, markedSpots, markSpot, clearSpots};
};
let player1 = Player('Player 1', 'X');
let player2 = Player('Player 2', 'O');
const gameLogic = (() => {
let currentPlayer = player1;
const reset = () => {
player1.clearSpots();
player2.clearSpots();
currentPlayer = player1;
};
return {startGame, reset};
})();
Above I have part of the code from a tictactoe game that I am trying to make. In the reset function I need to clear the array in the both player objects and set the current player back to player1. Through debugging, I know that calling the clearSpots() function does clear the array in the player objects. But there is a problem with reseting the currentPlayer. I believe this might be a closure problem, but I have no idea how to identify the problem or how to solve it. CAn anyone explain to me?
I suggest using a class instead. You could use the class syntax:
create a constructor with the player initialization logic saving the variables in this as properties
add methods to the class: here markSpot and clearSpots
instantiate new objects with new: let players1 = new Player(...)
Here is a code example:
class Player {
constructor(name, mark) {
this.markedSpots = [];
this.mark = mark;
this.name = name;
return this;
}
markSpot(spot) {
this.markedSpots.push(spot);
};
clearSpots() {
this.markedSpots = [];
};
};
let player1 = new Player('Player 1', 'X');
let player2 = new Player('Player 2', 'O');
const gameLogic = (() => {
let currentPlayer = player1;
const reset = () => {
player1.clearSpots();
player2.clearSpots();
currentPlayer = player1;
};
return {reset}; // removed startGame for demo purposes
})();
player1.markSpot(1);
console.log('before:', player1)
gameLogic.reset();
console.log('after:', player1)
Notice how you can access the object's property when inside the class with this: this.markedSpots, this.mark, this.name etc...
The issue is that when you call markedSpots = [];, you're changing the markedSpots reference.
This means that the returned markedSpots from earlier is not being changed, and instead only the markedSpots variable inside of the function's value is. When you try to access the returned markedSpots outside of the Player function, it is still referencing the original value, not the new empty one.
What you can do is replace markedSpots = []; with markedSpots.splice(0, markedSpots.length);, which will empty the array without changing the reference.
const Player = (name, mark) => {
let markedSpots = [];
const markSpot = (spot) => {
markedSpots.push(spot);
};
const clearSpots = () => {
markedSpots.splice(0, markedSpots.length); // <= Change is here.
};
return {name, mark, markedSpots, markSpot, clearSpots};
};
let player1 = Player('Player 1', 'X');
let player2 = Player('Player 2', 'O');
const gameLogic = (() => {
let currentPlayer = player1;
const reset = () => {
player1.clearSpots();
player2.clearSpots();
currentPlayer = player1;
};
return {reset};
})();
// Testing (should output two empty arrays):
player1.markSpot(1);
player1.markSpot(2);
player2.markSpot(3);
gameLogic.reset();
console.log(player1.markedSpots)
console.log(player2.markedSpots)
In the below code I am trying to print out just the first value (name) of the array, but it doesn't work as I expect:
function Person (name, age) {
this.name = name;
this.age = age;
}// Our Person constructor
// Now we can make an array of people
var family = new Array();
family[0] = new Person("alice", 40);
family[1] = new Person("bob", 42);
family[2] = new Person("michelle", 8);
family[3] = new Person("timmy", 6);
// loop through our new array
for(i = 0; i <= family.Length; i++) {
console.log( family[i].this.name);
}
You are using the "this" keyword incorrectly. When you access family[i] you are already accessing an instance of that prototype in JavaScript. Just drop the "this."
To get the first item from the array you could do the below without the loop:
console.log(family[0].name);
Without looping, as the loop is unnecessary if you know which item you want to print.
Or, if the loop is necessary you could add some logic such as
if(i === 0) {
console.log(family[0].name);
}
You do not need to use this when accessing the name property of the object in the array.
function Person (name, age) {
this.name = name;
this.age = age;
}// Our Person constructor
// Now we can make an array of people
var family = new Array();
family[0] = new Person("alice", 40);
family[1] = new Person("bob", 42);
family[2] = new Person("michelle", 8);
family[3] = new Person("timmy", 6);
// loop through our new array
for(i = 0; i < family.length; i++) {
console.log( family[i].name);
}
Make Unique Objects by Passing Parameters to our Constructor:
The constructor we have is great, but what if we don't always want to create the same object?
To solve this we can add parameters to our constructor. We do this like the following example:
var Car = function(wheels, seats, engines) {
this.wheels = wheels;
this.seats = seats;
this.engines = engines;
};
Now we can pass in arguments when we call our constructor.
var myCar = new Car(6, 3, 1);
This code will create an object that uses the arguments we passed in and looks like:
{
wheels: 6,
seats: 3,
engines: 1
}
Now give it a try yourself! Alter the Car constructor to use parameters to assign values to the wheels, seats, and engines properties.
Then call your new constructor with three number arguments and assign it to myCar to see it in action.
Please complete the code given below :
var Car = function() {
//Change this constructor
this.wheels = 4;
this.seats = 1;
this.engines = 1;
};
//Try it out here
var myCar;
Instructions :
Calling new Car(3,1,2) should produce an object with a wheels
property of 3, a seats property of 1, and an engines property of 2.
Calling new Car(4,4,2) should produce an object with a wheels
property of 4, a seats property of 4, and an engines property of 2.
Calling new Car(2,6,3) should produce an object with a wheels
property of 2, a seats property of 6, and an engines property of 3.
myCar should have number values for the wheels, seats, and engines
properties.
My attempt :
var Car = function() {
//Change this constructor
this.wheels = 4;
this.seats = 1;
this.engines = 1;
};
//Try it out here
var myCar = function(wheels, seats, engines) {
this.wheels = wheels;
this.seats = seats;
this.engines = engines;
};
var myCar = new Car(6, 3, 1);
Coding challenge answer for the link you added will be :
var Car = function(wheels, seats, engines) {
if(isNaN(wheels))
wheels = 0;
if(isNaN(seats))
seats = 0;
if(isNaN(engines))
engines = 0;
this.wheels = wheels;
this.seats = seats;
this.engines = engines;
};
//Try it out here
var myCar = new Car(2,6,3);
myCar = new Car(3,1,2);
myCar = new Car(4,4,2);
Run tests after adding this code. - all will pass
You answered already yourself:
var Car = function(wheels, seats, engines) {
//additional checks
if(isNaN(wheels))
wheels = 0;
if(isNaN(seats))
seats = 0;
if(isNaN(engines))
engines = 0;
this.wheels = wheels;
this.seats = seats;
this.engines = engines;
};
//Try it out here
var myCar = new Car(3,1,2);
console.dir(myCar);
myCar = new Car(4,4,2);
console.dir(myCar);
myCar = new Car(2,6,3);
console.dir(myCar);
I am working on a Person constructor function that takes a name and age as its parameters, and trying to implement a method that retrieves all the 'Person' instances current age value and outputs the average. Here's my code...
var Person = (function() {
//private state
var inst = 1;
function Person(name, age) {
this.name = name;
this.age = age;
Object.defineProperty(this, "age", {
get: function() {
return age;
},
set: function(num) {
age = num;
}
});
Object.defineProperty(this, "_id", {
value: inst++
});
}
//Attempt to return number of instances divided by all current Person weights
Person.prototype.aveAge = function() {
return inst;
};
return Person;
}());
var jim = new Person("jim", 32);
var richard = new Person("richard", 27);
richard.age = 28;
var alfie = new Person("alfie", 42);
Person.aveAge() //Returns TypeError: Person.aveAge is not a function
I have set up a variable that is shared across all instances (inst) that increments each time an another instance is created and assigns a unique id. I cannot figure out how I can get to each 'age' value of all Person instances in existence using the aveAge prototype I have added at the bottom. I am also getting a 'TypeError: Person.aveAge is not a function' when I attempt to call it to even test that variable 'inst' holds the correct number of instances. Does anybody know where I am going wrong?
It feels strange to keep ages on a person when it references people. Notice that hanging things on __proto__ makes them available from the constructor (Person), while hanging things on prototype makes them available from the instance (richard). If Age is updated, it needs to be done via setAge so the PeopleTracker knows to update it's memory. Also, in my example, the average is only calculated when needed rather than each time a person wants to know what is is.
var peopleTracker = {
_count: 0,
_ages: [],
averageAge: 0,
addPerson: function (age) {
var pt = peopleTracker;
pt._count += 1;
pt._ages.push(age);
pt.getAverage();
},
getAverage: function () {
var sum = 0,
pt = peopleTracker;
sum = pt._ages.reduce(function (a, b) {
return a + b;
});
pt.averageAge = Math.round(sum / pt._count);
},
update: function (oldAge, newAge) {
var pt = peopleTracker,
ages = pt._ages,
i = ages.indexOf(oldAge);
ages.splice(i, 1, newAge);
pt.getAverage();
}
};
var Person = function (name, age) {
this.name = name;
this.age = age;
peopleTracker.addPerson(age);
};
Person.__proto__ = { // available from the constructor
Constructor: Person,
setAge: function (age) {
var oldAge = this.age;
this.age = age;
peopleTracker.update(oldAge, age);
},
aveAge: function () {
return peopleTracker.averageAge;
}
};
Person.prototype = Person.__proto__; // now also available from the instance
var jim = new Person("Jim", 32),
richard = new Person("Richard", 27),
alfie = new Person("Alfie", 42);
Person.aveAge(); // 34
richard.aveAge(); // 34
richard.setAge(20);
Person.aveAge(); // 31
richard.aveAge(); // 31
I try to access an object which is global; it's a kind of a preset.
var perks = {health: 100, attack: 10};
var player = function(hp) {
this.stats = perks;
//Changing some standard values..
this.stats["health"] = hp;
}
var Peter = new player(200);
var Steven = new player(300);
I hope you get my intention; the problem is, that it won't work correct, and I'm not even sure what it does wrong. If I create more than one player, e.g. Steven, Collin and James, every player has the same perks. In this example Peter and Steven both have 300 health.
If I change the line
this.stats = perks;
to
this.stats = {health: 100, attack: 10};
everything works like intended. Peter and Steven both have their own stats.
How do I access the global var perks?
It happens because in JavaScript object does not copy that way, thats why all of your players using the same perks object.
There is a few ways to solve it:
Create new object with a function (object own constructor).
function createPerks() {
return {
health: 100,
attack: 10
};
}
var player = function(hp) {
this.stats = createPerks();
//Changing some standard values..
this.stats["health"] = hp;
}
var Peter = new player(200);
var Steven = new player(300);
Create new object each time and use constants for default values:
var BASE_HEALTH = 100;
var BASE_ATTACK = 10;
var player = function(hp) {
this.stats = {
health: BASE_HEALTH,
attack: BASE_ATTACK
};
//Changing some standard values..
this.stats["health"] = hp;
}
var Peter = new player(200);
var Steven = new player(300);
Use Object.create (works in IE9+, but shimable for older browsers):
var perks = {health: 100, attack: 10};
var player = function(hp) {
this.stats = Object.create(perks);
//Changing some standard values..
this.stats["health"] = hp;
}
var Peter = new player(200);
var Steven = new player(300);
Keep in mind that Object.create does not clone an object but inherit one object from another.
Object.create shim for old browsers by Douglas Crockford:
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
The moment you write this.stats = perks; both of them refer to the same object that is {health: 100, attack: 10}. So any changes made to any one of them will always affect the other.
As var Steven = new player(300); is the last value you assigned. All your players will now have {health: 300, attack: 10}