Javascript: allow certain classes to change properties of another class - javascript

I have Student class. The student has a grade.
Teacher class can change the student's grade.
Other classes (i.e., parent class) cannot do that. I think I get the part about how to change another class's property (please correct me if I'm wrong), but how to make sure that only the Teacher class can change the grade?
class Student {
grade = 'A';
changeGrade(grade) {
this.grade = grade
return `the new grade is ${this.grade}`
}
}
class Teacher {
changeStudentGrade(student, grade) {
return student.changeGrade(grade)
}
}

JavaScript does not support this functionality. However, you can still add suitable logic to facilitate it by checking the class that is trying to changeGrade within the method as follows:
changeGrade(grade, classChangingGrade) {
if (classChangingGrade instanceof Teacher) {
this.grade = grade
return `the new grade is ${this.grade}`
}
}
Then this method should be invoked as below:
return student.changeGrade(grade, this);
Disclaimer
Other classes can get around this by creating a new Teacher instance and invoking changeGrade as follows:
student.changeGrade(grade, new Teacher());

Related

How to create fields in a class using Symbol

I have class Movie. Movie constructor should provide a generation of unique product id within the application no matter how many products are created. You also need to define a field with the name of the movie. But according to the condition, for this I have to use Symbol data type. How can i do this?
class Movie {
constructor(name) {
//here I need to generate a unique id;
//here I need to define name fields
}
}
class Movie {
sym = Symbol('symbol description')
constructor(name) {
this.symInConstructor = Symbol('symbol description')
// this.sym != this.symInConstructor
// M1.sym == M2.sym <=> M1 == M2
}
}
// remeber, Symbol() != Symbol(), each call creates a unique one
However note that you can't ever serialize a Symbol.
If you need a serializable thingy, generate uuid or whatever
Also it may have sense to not use Symbol, but to use the class instance itself, I don't see how the Symbol may be used
Create a global constant, and use square brackets access
const MovieName = Symbol('a key for MovieName')
class Movie {
[MovieName] = "The Movie";
["myString"] = "is equivalent to:"
// myString = "is equivalent to:"
// and must be used for Symbols as
constructor() {
this[MovieName] = "The Movie in constructor"
}
// may keep is somewhere like this for usage in other places
static movieNameSymbol = MovieName
}

Class with grouped properties in deeper levels

I'm trying to build a complex class where I want to group properties, making the instantiated object have multiple layers, instead of every property being at root level.
So far, the only way I've found to do this is by making a class with the properties to group, and then in a "parent" class add a property of the class I built.
The problem here though is that two properties not sharing the same class can't communicate with each other.
There are ways around this, but I find them all very hacky and looking bad. One would be to create a hidden element, and store data in there that a property from another class can read.
Another would be to create static properties, but then, unless you do some major work with that property, you can only have one object created from the parent class, as it'll be the same no matter the instantiation of the class.
Very basic example:
class A {
constructor(prop1){
this.property = prop1;
}
}
class B {
constructor(prop2){
this.property = prop2;
}
}
class C {
constructor(prop1, prop2){
this.PropertyA = new A(prop1);
this.PropertyB = new B(prop2);
}
}
let obj = new C(1, 1);
console.log(obj.PropertyA.property);
In this example, the property from class A can't get a value from property in class B.
So, my question is, is there another way of building the class C to keep the levels of hierarchy in the object?
I use the class structure because I like how it looks. It looks far more readable to me than the prototype structure, and I'm not building an object directly, as I would like to instantiate more of them.
It feels like I have forgotten things I've looked at to try to do this, but I'm sure it'll come to me soon enough after I post this.
Sooo...
I worked a bit on a static-solution, and basically made a private static property to hold a unique id per instantiated object, with the key-value pairs I want to be able to share between the different classes. This should only expose the methods to either set or get those values. The only requirement is that all the classes needs to be constructed with the object ID, so they can get the right value.
I understand that people will roll their eyes at my infantile tries to break the actual points of classes and such, but it works for me anyway in this specific circumstance anyway.
I'm sure there a multitude of ways to update it to ensure it runs more smoothly, but I think it works for most cases at the moment.
The code made in example code:
"use strict";
class A {
#id
#testProp
constructor(id){
this.#id = id;
this.#testProp = 10;
}
get TestProp(){ return this.#testProp + C.getSharedProp(this.#id, "BValue")};
set TestProp(newValue) { this.#testProp = newValue; C.setSharedProp(this.#id, "AValue", this.#testProp) };
}
class B {
#id
#testProp
constructor(id){
this.#id = id;
this.#testProp = 10;
}
get TestProp(){ return this.#testProp + C.getSharedProp(this.#id, "AValue")};
set TestProp(newValue) { this.#testProp = newValue; C.setSharedProp(this.#id, "BValue", this.#testProp) };
}
class C {
#id
constructor(){
this.#id = Math.random().toString(36).substr(2, 9);
this.PropertyA = new A(this.#id);
this.PropertyB = new B(this.#id);
}
static #sharedProps = {};
static getSharedProp(charId, valueName) {
if(!charId){
throw "Must supply character ID";
}
if(!valueName){
throw "Must supply name of value to return";
}
if(!(charId in this.#sharedProps)){
throw "Character ID not found";
}
if(!(valueName in this.#sharedProps[charId])){
throw valueName + "-element not found";
}
return this.#sharedProps[charId][valueName];
}
static setSharedProp(charId, valueName, value) {
if(!charId){
throw "Must supply character ID";
}
if(!valueName){
throw "Must supply name of value";
}
if(!(charId in this.#sharedProps)){
this.#sharedProps[charId] = [];
}
if(!(valueName in this.#sharedProps[charId])){
this.#sharedProps[charId][valueName] = -1;
}
if(!value){
console.warn("Value not supplied of " + valueName + ". Not updating extant value");
}else{
this.#sharedProps[charId][valueName] = value;
}
}
}
let obj = new C();
obj.PropertyA.TestProp = 20;
obj.PropertyB.TestProp = 5;
console.log(obj.PropertyA.TestProp); //should be 25; 20 from its own class and 5 from foreign class-object
console.log(obj.PropertyB.TestProp); //should be 25; 5 from its own class and 20 from foreign class-object

Class syntax with parametrized class name

I want create classes dynamicaly in runtime, and I want parametrize the class name.
function newClass(className:string) {
return class MyDynamicClass { }
}
// expected class name: "Person"
let personClass = newClass("Person")
// expected class name: "Contact"
let contactClass = newClass("Contact")
P.S.: The proposed duplicate question (ES6 Dynamic class names) is with wrong accepted answer and other answers does not fulfil my requirements.
I don't think it is possible to make dynamic class name like here:
class [className] {}
It is not allowed.
However, you can create an object with className property (class expression):
const newClass = (className: string) => ({
[className]: class { }
}[className])
// expected class name: "Person"
let personClass = newClass("Person")
personClass.name // Person
I know, personClass returns class {} without name. I think this is the closest working solution.

Creating a class in JS OOP

Can You help with this thing that I need to figure out. I started learning Js with OOP but I am kind of stuck with this, where am I making a mistake. This is the assignment I have to figure out
Create a class Car with a property that holds a number of doors and one method that prints the number of doors to the console.
class Car {
constructor(doors){
this.doors=doors
console.log(doors)
}
}
you need to create a method in the Car class to print the number of doors and then you need to instantiate the class with a given number of door & then call that method on it.
class Car {
constructor(doors){
this.doors = doors;
}
print(){
console.log(this.doors);
}
}
const bmw = new Car(4);
bmw.print()
Hey 👋
Yeah no problem :)
class Car {
constructor(doors) {
this.doors = doors;
}
printDoors() {
console.log(this.doors);
}
}
In JS OOP you have to define your member variables within the constructor by using the this keyword.
To access your variables somewhere else in the class you also have to use `this.
The printDoor() function has to be defined at its own to call it later on like this:
const numberDoors = 4;
const myCar = new Car(numberDoors);
myCar.printDoors();
// expected output: 4

Make long path codes shorter in java

I am pretty new to programming so I am not sure what this is called but in Javascript, for example
arr[0].obj[0].getSomething();
can be shorten to
var o = arr[0].obj[0];
o.getSomething();
so that we do not have to repeat
arr[0].obj[0]
what is the equivalent of this in Java? I can't seem to find it.
Also tell me what should the title be, I am not sure whether my title is appropriate.
You do it just the same way:
If you have
House[] houses; // An array of houses
// initialize and fill the array
... and inside the House class you have a field doors:
public class House {
Door[] doors;
// Initialize the array in a constructor, add getter and setter methods
}
Then you can do either
Color doorColor = houses[0].doors[0].getColor();
or you store the door you want in a variable and then ask for its color:
Door door = houses[0].doors[0];
Color doorColor = door.getColor();
With the given snipped I can understand your java code would look like as below.
class A{
B obj[];
}
class B {
public void doSomething(){}
}
lets say you have array of A class object as as your code snippet says
arr[0].obj[0].getSomething();
in java it would be of class A like below
A arr[]
so the code would be
arr[0].obj[0].doSomething();
we can write it as
A firstA = arr[0];
B firstB = firstA.obj[0];
firstB.doSomething();
or
B firstB = arr[0].obj[0];
firstB.doSomething();

Categories