Using class method to execute callback from another class instance [duplicate] - javascript

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 months ago.
class Player {
constructor() {
this.health = 100;
}
playerDamaged(applyDamage) {
applyDamage(this);
}
}
class BrickWall {
constructor() {
this.collisionDmg = 5;
}
playerCollision(player) {
player.health -= BrickWall.collisionDmg;
}
}
class SpikyWall {
constructor() {
this.collisionDmg = 25;
}
playerCollision(player) {
player.health -= SpikyWall.collisionDmg;
}
}
const player = new Player();
const brickWall = new BrickWall();
const spikyWall = new SpikyWall();
player.playerDamaged(brickWall.playerCollision);
player.playerDamaged(spikyWall.playerCollision);
console.log(player.health);
In the Player class I want to be able to pass a callback to playerDamaged to apply damage to the Player's health.
My intended objective is that line when player.playerDamaged(brickWall.playerCollision); runs, the player's health will be reduced by 5, and when player.playerDamaged(brickWall.playerCollision); runs, the player's health will be reduce by another 25.
I want console.log(player.health); to return 70. It currently returns NaN.
Thanks for any assistance you can offer!

With this
player.health -= BrickWall.collisionDmg;
you're referring to BrickWall.collisionDmg - which would only make sense if the property is on the class itself, like so:
class BrickWall {
static collisionDmg = 5;
playerCollision(player) {
player.health -= BrickWall.collisionDmg;
}
}
or
class BrickWall {
playerCollision(player) {
player.health -= BrickWall.collisionDmg;
}
}
BrickWall.collisionDmg = 5;
The class is not the instance; the instance does not inherit from the class as a prototype. (The instance inherits from the <class>.prototype, but not from <class>) So, since no property exists at BrickWall.collisionDmg in your code, it returns undefined, resulting in NaN.
Add the static properties.
class Player {
constructor() {
this.health = 100;
}
playerDamaged(applyDamage) {
applyDamage(this);
}
}
class BrickWall {
static collisionDmg = 5;
playerCollision(player) {
player.health -= BrickWall.collisionDmg;
}
}
class SpikyWall {
static collisionDmg = 25;
playerCollision(player) {
player.health -= SpikyWall.collisionDmg;
}
}
const player = new Player();
const brickWall = new BrickWall();
const spikyWall = new SpikyWall();
player.playerDamaged(brickWall.playerCollision);
player.playerDamaged(spikyWall.playerCollision);
console.log(player.health);
That said, I don't think having classes for BrickWall and SpikyWall are doing that much for you here (other than making the logic uncomfortably weird to follow due to the callbacks). A class is useful when you want to tie together data associated with an instance with methods to operate on that data - but you don't have any instance data. JS isn't Java, so don't feel like you have to use a class just because the keyword exists. Consider a plain function instead, and then call that function, perhaps like:
const brickWall = player => player.health -= 25;
or
const COLLISION_DAMAGE = {
brickWall: 5,
spikeyWall: 25,
};
// ...
player.playerDamaged(COLLISION_DAMAGE.brickWall);

Related

p5.js Instance Mode: How to access the instance variables from inside a class

I'm having trouble using p5js in instance mode. I split my code into multiple files for easier maintenance, separating classes from the main sketch file.
Inside the classes i need access to variables declared in the main sketch but i get undefined when i inject the sketch object into the class.
Ideally i would like to have access to ANY variables declared in the main sketch file. Is it possible/recommended?
Here is a minimum case example of what i'm trying to achieve:
index.js
import p5 from "p5"
import TestClass from "./_testClass";
let sketch = new p5( (p) => {
let myColor = 75;
p.setup = function() {
p.createCanvas(1000,1000);
let t = new TestClass(100,100)
t.render(p)
}
}, "p5");
_testClass.js
export default class TestClass {
constructor(x,y) {
this.x = x;
this.y = y;
}
render(p) {
p.rect(this.x, this.y, 50, 50); // i get a square on the canvas: p.rect() is recognized
console.log(p.myColor); // undefined
}
}
Any variables that you want to be available within the TestClass's render() function either need to be 1) passed to the TestClass constructor, 2) passed to the render function, 3) declared/assigned on/to the p5 instance, or 4) declared globally.
For instance mode sketches it is not uncommon to add things to the p5 instance:
import p5 from "p5"
import TestClass from "./_testClass";
let sketch = new p5((p) => {
// let myColor = 75;
p.myColor = 75;
p.setup = function() {
p.createCanvas(1000,1000);
let t = new TestClass(100,100)
t.render(p)
}
}, "p5");
However, I think it would be better OOP practice to pass this to your TestClass constructor:
import p5 from "p5"
import TestClass from "./_testClass";
let sketch = new p5((p) => {
let myColor = 75;
p.setup = function() {
p.createCanvas(1000, 1000);
let t = new TestClass(100, 100, myColor)
t.render(p)
}
}, "p5");
export default class TestClass {
constructor(x, y, rectColor) {
this.x = x;
this.y = y;
this.rectColor = rectColor;
}
render(p) {
console.log(this.rectColor);
p.fill(this.rectColor);
p.rect(this.x, this.y, 50, 50);
}
}

Get Private Method Value at Public Method in JavaScript

I have Created a Class Circle. Here
_radius is a private parameter
_areaCalculate is a private method
After Calculate the value from private method _areaCalculate. I need this value to public method areaPrint. But it show me undefined.
const _radius = new WeakMap()
const _areaCalculate = new WeakMap()
class Circle {
constructor(r) {
_radius.set(this, r)
}
[_areaCalculate]() {
return (Math.PI * Math.pow(this.radius, 2)).toFixed(2)
}
areaPrint() {
console.log("The area of Circle is: " + _areaCalculate.get(this))
}
}
let c = new Circle(4)
c.areaPrint()
If one sticks with the OP's approach of utilizing a weak map for accessing a Circle instance' "private member" through a prototypal method, then one just needs to simplify the code to a single reference map and a function which calculates a circle instance' area on the fly ...
function getComputedArea(circle) {
return (Math.PI * Math.pow(rMap.get(circle), 2)).toFixed(2);
}
const rMap = new WeakMap();
class Circle {
constructor(radius) {
rMap.set(this, radius);
}
areaPrint() {
console.log(
`A radius ${ rMap.get(this) } circle area is ${ getComputedArea(this) }`
);
}
}
let a = new Circle(4);
let b = new Circle(9);
a.areaPrint();
b.areaPrint();
... or one follows VLAZ's advice and starts utilizing the private field declaration syntax for private instance fields.
Edit
From the further beneath comment-based discussion with Bergi ...
"Private methods, unlike private fields, are allocated on the prototype not on the instance, just the like their respective public counterparts" . – Bergi
... the implementation for getComputedArea changed from a local helper function to a private instance method.
class Circle {
#getComputedArea(radius) {
return (Math.PI * Math.pow(this.#radius, 2)).toFixed(2);
}
#radius;
constructor(radius) {
this.#radius = radius;
}
areaPrint() {
console.log(
`A radius ${ this.#radius } circle area is ${ this.#getComputedArea() }`
);
}
}
let a = new Circle(4);
let b = new Circle(9);
a.areaPrint();
b.areaPrint();

Difficulty getting functions to work in my Javascript class

Clearly, a new developer! Thank you for replying in advance, I know the answer must be really simple but I have been stuck for an hour.
This exercise asks to create a class and then asks to change some of the dynamic values using class methods/functions. I am not able to get my values to change when I call the function.
Here are the directions for the exercise, followed by my code, sorry that my work looks so rudimentary!
These are the directions:
// Create a new class called SuperHero
// - Your class should have the following DYNAMIC values
// - name
// - superpower
// - age
// - Your class should have the following STATIC values
// - archNemesis, assigned to "The Syntax Error"
// - powerLevel = 100
// - energyLevel = 50
//Where I start having issues is here:
// - Create the following class methods
// - sayName, should print the hero's name to the console
// - maximizeEnergy, should update the energyLevel to 1000
// - gainPower, should take an argument of a number and INCREASE the powerLevel //by that number
class SuperHero {
constructor(name, superpower, age,){
this.name = name;
this.superpower = superpower;
this.age = age;
this.archNemesis = "The Syntax Error";
this.powerLevel = 100;
this.energyLevel = 50;
}
var power = 20;
sayName() {
console.log(this.name);
}
maximizeEnergy() {
this.energyLevel = 1000;
}
gainPower(power) {
this.powerLevel = this.powerLevel + power;
}
};
var superHero1 = new SuperHero("Batman", "strength", 40);
Thanks again! :)
Well, you code is 80% correct. Only issues I see is the this.energyLevel(1000); and sayName() method. They are not really required.
this.energyLevel is a property and not a function, so calling it like this.energyLevel(1000); is wrong. You should be setting this value as this.energyLevel = 1000;
sayName() is not really doing anything useful. You are already setting/initializing the name in the constructor.
Here is a simple example of a class and how to use it's methods for changing it's property values. Check the output in your browser console.
class SuperHero {
constructor(name, superpower, age, archNemesis, powerLevel, energyLevel) {
this.name = name;
this.superpower = superpower;
this.age = age;
this.archNemesis = "The Syntax Error";
this.powerLevel = 100;
this.energyLevel = 50;
}
maximizeEnergy() {
this.energyLevel = 1000;
}
gainPower(gainPower = 20) {
this.powerLevel += gainPower;
}
}
var superHero1 = new SuperHero("Batman", "strength", 40, "The Joker", 100, 50);
var superHero2 = new SuperHero("Wonder Woman", "agility", "Cheetah", 1000, 1000);
console.log('name', superHero1.name);
console.log('superpower',superHero1.superpower);
console.log('archNemesis',superHero1.archNemesis);
console.log('energyLevel',superHero1.energyLevel);
superHero1.gainPower(100);
console.log('powerLevel',superHero1.powerLevel);
console.log('-------------------------------------');
console.log('name', superHero2.name);
console.log('superpower',superHero2.superpower);
console.log('archNemesis',superHero2.archNemesis);
console.log('energyLevel',superHero2.energyLevel);
superHero2.gainPower(200);
console.log('powerLevel',superHero2.powerLevel);
you probably want to do things more like this:
sayName() {
console.log(this.name);
}
maximizeEnergy() {
this.energyLevel = 1000;
}
gainPower(power) {
this.powerLevel = this.powerLevel + power;
}
They are all pretty self explanatory.

Unexpected identifier count

I try to count how much ice-creame i will have. i can add and delete icecreame.
class Ice-creame {
constructor (size) {
this.size = size;}
function crCount(){
let Count = 0;
crCount.prototype.inc = function () {
Count++;};
crCount.prototype.dec = function () {
Count--;};
crCount.prototype.getValue = function () {
return Count};
}
let counter = new crCount();
addToping () {
{
this.counter.inc()}
}
}
let size1 = new Ice-creame('size1');
small1.addToping();
counter.getValue();
for example , i have ice-creame size 1 , after 2 times addToping, getValue must be 2
You can't have - in Javascript variable names such as Ice-cream. you need to remove the - from it.
And why are you defining a class inside another class and mixing old class definition syntax with the new one !
Your code could be much simpler like this:
class IceCream {
constructor(size) {
this.size = size;
this.crCount = 0;
}
addTopping() {
this.crCount += 1;
}
removeTopping() {
this.crCount -= 1;
}
getValue() {
return this.crCount;
}
}
const icecream = new IceCream("size1");
icecream.addTopping();
console.log(icecream.getValue());

How can I use composition with methods in ES6 Classes?

I am struggling to implement composition in ES6 classes! I am trying to understand a lot of things at once and have maybe made a stupid error.
I would like to avoid inheritance using extend and super for now, and have found this nice example of composition that seems to show what I am after:
class EmployeeTaxData {
constructor(ssn, salary) {
this.ssn = ssn;
this.salary = salary;
}
// ...
}
class Employee {
constructor(name, email) {
this.name = name;
this.email = email;
}
setTaxData(ssn, salary) {
this.taxData = new EmployeeTaxData(ssn, salary);
}
// ...
}
In regard to the code below, I would like to use the most simple and eloquent way to make the spin() method available for the objects created by the Hero class so it is using a shared prototype. I would like to share this method with other objects that will need it too.
Unfortunately I can't make my code work as the this.angle is not referring to to the Hero class that it needs to, but the Spinner class?
class Spinner {
constructor(direction){
this.direction = direction;
}
spin(direction) {
switch (direction) {
case 'left':
this.angle -= 1;
break;
case 'right':
this.angle += 1;
break;
// no default
}
}
}
class Hero {
constructor(xPosition, yPosition) {
this.description = 'hero';
this.width = 25;
this.height = 50;
this.xPosition = xPosition;
this.yPosition = yPosition;
this.angle = 0;
this.color = 'red';
this.spin = new Spinner();
}
spin() {
this.spin.spin();
}
}
const heroClass = new Hero(100, 200);
console.log(heroClass.angle); // result is 0
heroClass.spin.spin('left');
console.log(heroClass.angle); // result is STILL 0, it didn't work
...the this.angle is not referring to to the Hero class that it needs to, but the Spinner class?
As it should. When you're inside the spinner class, then this refers to a spinner object, which also means this.angle inside the spinner class refers to an angle property of a spinner object.
You'll probably want spinner to return a new angle value, then the hero object that uses spinner should save the returned new angle value.
class Spinner {
constructor(direction){
this.direction = direction;
}
spin(direction, angle) {
switch (direction) {
case 'left':
angle -= 1;
break;
case 'right':
angle += 1;
break;
// no default
}
return angle;
}
}
class Hero {
constructor(xPosition, yPosition) {
this.description = 'hero';
this.width = 25;
this.height = 50;
this.xPosition = xPosition;
this.yPosition = yPosition;
this.angle = 0;
this.color = 'red';
this.spinner = new Spinner();
}
spin(direction) {
this.angle = this.spinner.spin(direction, this.angle);
}
}
const heroClass = new Hero(100, 200);
console.log(heroClass.angle); // result is 0
heroClass.spin('left');
console.log(heroClass.angle); // result is -1
I had to make a few other small changes for this to work. For example, you had a data property named "spin" this.spin = new Spinner as well as a method named spin spin() {. They were overriding one another.

Categories

Resources