This is a short piece of code from mazeContainer.js with only necessary part-
import Cell from "./cell.js";
import Player from "./player.js";
export default class Maze {
....
setup(){
for (let rowNum = 0; rowNum < this.rows; rowNum++) {
let row = [];
for (let colNum = 0; colNum < this.columns; colNum++) {
let cell = new Cell(this.ctx, rowNum, colNum, this.cellWidth, this.cellHeight);
row.push(cell);
}
this.grid.push(row);
}
drawMap(){
....
let player = new Player(this.goal, this.lastRow, this.lastColumn);
....
}
}
And player.js-
import Cell from "./cell.js";
export default
class Player extends Cell {
constructor(goal, lastRow, lastColumn) {
super(); // need to manage this statement
this.goal = goal;
this.lastRow = lastRow;
this.lastColumn = lastColumn;
}
....
}
Now here's what I'm having trouble with.
I've just encountered the super keyword and what I've got to know so far is that I need to call super method before using this. That's not an issue. But here I also need to provide all parameters for Cell's constructor.
As you can see, the Cell class has got many parameters in its constructor, so how do I hand them over to new Player(....)?
Is there a better way to achieve this?
• The extends keyword makes the methods of the animal class available inside the cat class.
• The constructor, called when you create a new Cat object, accepts two arguments, name and usesLitter.
• The super keyword calls the constructor of the parent class. In this case, super(name) passes the name argument of the Cat class to the constructor of the Animal class. When the Animal constructor runs, it sets this._name = name; for new Cat instances.
• _usesLitter is a new property that is unique to the Cat class, so we set it in the Cat constructor.
class Animal {
constructor(name) {
this._name = name;
}
get name() {
return this._name;
}
}
class Cat extends Animal {
constructor(name, usesLitter) {
super(name); // The super keyword calls the constructor of the parent class.
this._usesLitter = usesLitter;
}
get usesLitter() {
return this._usesLitter;
}
}
const bryceCat = new Cat('Bryce', true);
console.log(bryceCat.name); //Output: Bryce
console.log(bryceCat.usesLitter); //Output: true
Related
I would like to call a method from the great grandfather to the Athlete class,
How can I do that?
I tried using super.printSentence but that did not work,
Is this the correct way to invoke the method, super.printPositon() in the Athlete class?
Any suggestion on how to invoke this printSentence method?
class Person {
constructor(name) {
this.name = name;
}
printName() {
console.log(this.name);
}
}
class TeamMate extends Person {
constructor(name) {
super(name);
}
printSentence() {
console.log(super.printName(), "is an excellent teammate!" );
}
}
class SoccerPlayer extends TeamMate {
constructor(name, teamMateName, position) {
super(name, teamMateName);
this.teamMateName = teamMateName;
this.position = position;
}
printPositon() {
console.log("Positon: ", position);
}
}
class Athlete extends SoccerPlayer{
constructor(name, teamMateName, position, sport) {
super(name, teamMateName, position);
this.sport = sport;
}
printSport() {
console.log("Favorite sport: ", this.sport);
}
//If Athlete class extends from SoccerPlayer and SoccerPlayer extends from
// the TeamMate class, how can I invoke the printSentence method
// from the TeamMate class in this current Athlete class?
printGreatGrandFatherMethod() {
return this.printSentence()
}
}
const soccerPlayer = new Athlete('PLAYER1', 'Frederick', 'Defender', 'Soccer');
console.log(soccerPlayer.printGreatGrandFatherMethod());
Why am I getting undefined for the name field?
Just to this.printSentence()
In inheritance (prototype or not) the this has access to all the methods.
Unless you are using private method like this:
class ClassWithPrivateMethod {
#privateMethod() {
return 'hello world';
}
}
If you think about it, if a Person has a name any class that inherited from Person will also have a member name. This is also true to any instance of a class that inherits from Person. for example:
const soccerPlayer = new SoccerPlayer('PLAYER1', 'MATE NAME', '1');
console.log(soccerPlayer.name); // Prints `PLAYER1`
printSentence() doesn't return a value, so return this.printSentence() will return undefined. And since that's what printGreatGrandFatherMethod returns, therefore console.log(soccerPlayer.printGreatGrandFatherMethod()); will log undefined.
Same goes for printName() which doesn't return a value either and therefore console.log(super.printName()) will log undefined
I have for example this class:
abstract class MyClass {
abstract myProp: number;
constructor() {
// Some code
}
}
So I want to create multiple classes that extends this class. But I don't want to repeat it multiple times as I will have a lot of classes. So the purpose is that each class has a different name and myProp.
For example:
class FirstClass extends MyClass {
myProp = 1;
constructor() {
super();
// Some code
}
}
class SecondClass extends MyClass {
myProp = 2;
constructor() {
super();
// Some code
}
}
So I want to generate these classes (with for example a function) but the problem is that I will have to use the new keyword.
So the usage for each of these classes should be like this:
const myConst = new FirstClass();
const myConst2 = new SecondClass();
I hope this makes some sense. I just don't want to repeat every class because it has a different name and myProp.
You can create classes through a function that returns an anonymous class.
const createClass = ( prop: number ) => {
return class extends MyClass {
myProp: number;
constructor () {
super();
this.myProp = prop;
}
}
}
const FirstClass = createClass(1);
const x = new FirstClass();
console.log(x.myProp);
Or check out the answers to these questions for ideas:
ES6 Dynamic class names
Create object from class name in JavasScript ECMAScript 6
If I understand your problem correctly, you could just pass the variable that's different as an argument in the constructor.
class MyClass {
myProp: number;
constructor(myProp: number) {
this.myProp = myProp
// Some code
}
}
And then create the class instances you want.
const myConst = new MyClass(1);
const myConst2 = new MyClass(2);
Personally, I would only extend a class if I want to add some methods or properties that aren't shared. Since myProp exists in both classes, it's probably better to just pass the value to the constructor.
I have two classes. I want to access type property of Parent from instance:
// Parent class
function Animal() { this.type = 'animal' }
// Child class
function Rabbit(name) { this.name = name }
// I inherit from Animal
Rabbit.prototype = Object.create(Animal.prototype);
Rabbit.prototype.constructor = Rabbit; // I want to keep Rabbit constructor too
// I instantiate my Rabbit and am trying to access rabbit.type
const rabbit = new Rabbit('Bunny');
rabbit.name // => Bunny
rabbit.type // => undefined. WHY?
I know how to solve it and access type, but...
// all is the same
// Child class
function Rabbit(name) {
Animal.apply(this, arguments); // Just need to add this line in Rabbit class
this.name = name
}
// all is the same
rabbit.name // => Bunny
rabbit.type // => animal
...but why it doesn't work in the first example? Is it possible to achieve it without using Animal.apply?
Yes, if you would add type to the prototype:
Animal.prototype.type = "animal";
Or you could hide the Animal.apply call behind the class sugar:
class Animal {
constructor() {
this.type = "animal";
}
}
class Rabbit {
constructor(name) {
super(); // <<<
this.name = name;
}
}
Rabbit.prototype = Object.create(Animal.prototype); only extends the properties defined in the prototype chain. The properties defined within the constructor won't get extended.
Try this,
...
Rabbit.prototype = new Animal();
...
Updated Example:
// Parent class
function Animal() { this.type = 'animal' }
// Child class
function Rabbit(name) { this.name = name }
Rabbit.prototype = new Animal();
Rabbit.prototype.constructor = Rabbit;
const rabbit = new Rabbit('Bunny');
console.log(rabbit.name);
console.log(rabbit.type);
I would like to ask what I am doing wrong here
My goal
I want to create instances from a class constructor.
The first is gonna be a more generic class called Person and then another that will inherit properties from that class.
My question is
When all classes are set and the first instance that points to the Person constructor is declared, how could the pass the key: values of the previous instance to the next instance since I don't want to repeat my self over the same arguments.
I am currently spreading the previous parameters of the instance but obviously, I am doing something wrong.
class Person {
constructor (name,yearOfBirth,job) {
this.name = name;
this.yearOfBirth = yearOfBirth;
this.job = job;
}
getAge() {
return new Date().getFullYear() - this.yearOfBirth
}
greet(){
return `${this.name} is a ${this.getAge()} years old ${this.job}`
}
}
class footballPlayer extends Person {
constructor(name,yearOfBirth, job, team, cups) {
super(name, yearOfBirth, job)
this.team = team;
this.cups = cups;
}
cupsWon() {
console.log(`${this.name} who was bord on ${this.year} and works as a ${this.job} won ${this.cups} with ${this.team}`);
}
}
const vagg = new Person('vaggelis', 1990, 'Developer');
const vaggA= new footballPlayer( {...vagg} , 'real madrid', 4)
console.log(vagg.greet());
console.log(vaggA.cupsWon());
Thank you!
If I understand correctly what you want to do, you need to pass only the values of the parameters that describe the Person to the footballPlayer (note: class names should by convention be uppercase).
var vaggA = new footballPlayer( ...Object.values(vagg) , 'real madrid', 4);
Edit: In case you fear a different order with Object.values (which is a real threat), you can create a getter function in the Person class that will return the exact list of parameters in the order they are supposed to be given to the constructor:
class Person {
// ...
describe() {
return [this.name, this.yearOfBirth, this.job];
}
}
const vaggA = new footballPlayer( ...vagg.describe() , 'real madrid', 4);
Assume that class Cheddar inherits from a class which expects an object as a parameter; essentially composition:
class Brand {
constructor(b) {
this.brand = b;
}
getBrand() {
return this.brand;
}
}
class Cheese {
constructor(brand_obj) {
// do stuff...
}
}
1
class Cheddar extends Cheese {
constructor(b) {
super(new Brand(b)); // <-- HERE, I'm a "one-liner" kinda guy :D
}
}
Now when I instantiate:
let snack = new Cheddar("Cabot Clothbound");
I can't access the Brand object, because it was created as an argument.
So, I tried to create the Brand and put it on the object before calling super, like this:
2
class Cheddar extends Cheese {
constructor(b) {
this.brand = new Brand(b);
super(this.brand);
}
}
...which results in the following error:
'this' is not allowed before super()
Grr.. so, I could do it this way:
3
class Cheddar extends Cheese {
constructor(b) {
let myBrand = new Brand(b);
super(myBrand);
this.brand = myBrand;
}
getBrand() {
return this.brand.getBrand();
}
}
And I can now happily access the methods on the cheese object like so:
let snack = new Cheese("Cabot Clothbound");
console.log(snack.getBrand()); //-> Cabot Clothbound
...but, it's getting messy. I want to be a "one-liner guy."
Anyway to access the object created as an argument to this constructor, or can I possibly structure things a bit differently to make this easier? I feel like I'm working too hard here. Thx, Keith :^D
You are not finishing the construction of Cheese. Your // do stuff should include saving the brand_obj if you want to access it from subclasses.
When you call super(new Brand(b)) the brand object will end up in the super class's constructor. But you aren't doing anything with it there. If save the brand as a property on the super class it will be available to the subclass:
class Brand {
constructor(b) {
this.brand = b;
}
getBrand() {
return this.brand;
}
}
class Cheese {
constructor(brand_obj) {
this.brand = brand_obj // <= save this!!
}
}
class Cheddar extends Cheese {
constructor(b) {
super(new Brand(b));
console.log("brand in cheddar constructor", this.brand) //<== now you can use it
}
}
let snack = new Cheddar("Cabot Clothbound");
console.log("Brand on instance: ", snack.brand)