I am having a parent class with a private property with a setter function. In my derived class I want to override the setter function and additionally I want access a private variable from within the derived class:
class Mother
{
#name
constructor()
{
this.name = "Paula";
}
set name(aName)
{
this.#name = aName;
}
get name()
{
return this.#name;
}
}
class Child extends Mother
{
#tattooText
constructor()
{
super();
this.#tattooText = null;
}
set tattooText(value)
{
this.#tattooText = value;
}
get tattooText()
{
return this.#tattooText;
}
set name(aName)
{
super.name = aName;
if (this.#tattooText === null)
this.#tattooText = aName;
}
get name()
{
return super.name;
}
}
Unfortunatelly, this will not work, because I dont have access to the private #tattooText property from within the derived class. Seems like the overwritten "set name" function is getting executed in the scope of the parent class.
Do you have any idea how to solve this task? How can i get access to private properties of a derived class from within an overwritten setter function?
Regards
Robert
Edited: The problem only appears, when I try to "prefill" the name property from within a constructor in the Mother-Class. (see edited source)
Related
In my Javascript class Order, I have a static method and a non-static method, and they both contain the same code. If possible, how would one of these methods inherit the code from the other? This is an attempt to make my code look more readable since it's becoming quite unwieldy.
You can use classes and inheritance, create a parent class and then a subclass. The extends keyword makes the methods of the parent class available inside the child class.
The super keyword calls the constructor of the parent class.
//Parent class (superclass)
class Animal {
constructor(name) {
this._name = name;
}
get name() {
return this._name;
}
}
//Child class (subclass)
class Cat extends Animal {
constructor(name, usesLitter) {
super(name);
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
To create a static method you can use the static keyword. For example, generateName() you can call it directly from the class, but not from an instance of the class.
class Human {
constructor(name) {
this._name = name;
static generateName() {
const names = ['Angel', 'Pedro', 'Luis', 'Mario', 'Julio'];
const randomNumber = Math.floor(Math.random()*5);
return names[randomNumber];
}
}
console.log(Human.generateName()); // Returns a random name.
I'd like to access private fields of base class from derived classes without making them public (what is called 'protected' in other languages).
Consider the following class:
class Animal {
#privateProp;
constructor() {
this.#privateProp = 12;
}
}
Now the extending class:
class Cat extends Animal {
constructor() {
super();
}
doIt() {
console.log(this.#privateProp) // 1 below
console.log(super.#privateProp) // 2 below
}
}
I'd like to execute as if it was protected:
new Cat().doIt();
But gets (respectively):
Uncaught SyntaxError: Private field '#privateProp' must be declared in an enclosing class
Uncaught SyntaxError: Unexpected private field
Notice that this code would work perfectly when privateProp becomes public, But I want to achieve a protected like behavior and get access to the 'private' fields like any language that support inheritance.
Any help will be appreciated.
you can create a private property with getter and setter methods
having restricted access by checking if the constructor is not of the
parent class itself.
class Animal {
#privateProp = 12;
set Prop(val) {
if (this.constructor.name !== 'Animal')
return this.#privateProp = val;
throw new Error('Cannot Access Protected property');
}
get Prop() {
if (this.constructor.name !== 'Animal')
return this.#privateProp;
throw new Error('Cannot Access Protected property');
}
}
class Cat extends Animal {
get Prop() {
return super.Prop;
}
set Prop(val) {
super.Prop = val
}
}
let cat = new Cat();
console.log(cat.Prop)
cat.Prop = 22
console.log(cat.Prop)
console.log(new Animal().Prop);
Fields are private in a similar way to how variables are block-scoped; if a property is private to a certain class, it may only be referenced inside that class. If you extend the class, it won't be visible in the derived class.
You could make a getter/setter on the superclass, if you want to be able to do stuff with it from the subclass:
class Animal {
#privateProp = 12;
setProp(val) {
this.#privateProp = val;
}
getProp() {
return this.#privateProp;
}
}
class Cat extends Animal {
doIt() {
console.log(this.getProp());
}
}
new Cat().doIt();
Another way is to define the "private" field as a WeakMap scoped only to the class declarations instead:
const { Animal, Cat } = (() => {
const privateProps = new WeakMap();
class Animal {
constructor() {
privateProps.set(this, 12);
}
}
class Cat extends Animal {
doIt() {
console.log(privateProps.get(this));
}
}
return { Animal, Cat };
})();
new Cat().doIt();
I have an abstract class with an abstract method that is implemented by the child class. The implemented method in the child class should update an private instance variable of the child class. After this I want to retrieve the value of the private variable by using a getter method.
To see the problem in action I have created some sample code in playground.
Animal is the base class with the abstract method someAbstractMethod():
abstract class Animal {
protected abstract someAbstractMethod(): void;
constructor() {
document.writeln("A new animal is born<br>");
this.someAbstractMethod(); // <-- call into child class
}
}
Snake inherits from Animal and implements the abstract method someAbstractMethod(). This class has a getter/setter to retrieve the value of the private instance variable someLocalVariable:
class Snake extends Animal {
private someLocalVariable: string = "intial value";
constructor() {
super();
}
get someValue() {
document.writeln("Called getter for someValue<br>");
return this.someLocalVariable;
}
set someValue(value: string) {
document.writeln("Called setter for someValue<br>");
this.someLocalVariable = value;
}
protected someAbstractMethod() {
document.writeln("Called someAbstractMethod()<br>");
this.someLocalVariable = "now set to something new"; // <-- instance variable not updated (or in another scope)
}
}
First create a new Snake and then get the value of the private instance variable by using a getter call to sam.someValue:
let sam = new Snake();
document.writeln("Value of someValue: " + sam.someValue);
Unexpected Result
Printed Log:
A new animal is born
Called someAbstractMethod()
Called getter for someValue
Value of someValue: intial value
sam.someValue returns 'initial value', but actually the method someAbstractMethod() was called before and should have set the value to 'now set to something new'
After reading this related question, I found an answer to my question.
My solution
The only change was in class Snake. I have removed the assignment to the variable someLocalVariable.
class Snake extends Animal {
private someLocalVariable: string; // = "intial value"; <--- remove assignment
constructor() {
super();
}
get someValue() {
document.writeln("Called getter for someValue<br>");
return this.someLocalVariable;
}
set someValue(value: string) {
document.writeln("Called setter for someValue<br>");
this.someLocalVariable = value;
}
protected someAbstractMethod() {
document.writeln("Called someAbstractMethod()<br>");
this.someLocalVariable = "now set to something new";
}
}
Updated code in playground
The problem was that the initialization of someLocalVariable is done AFTER the constructor call. someAbstractMethod() is called from the super.constructor and actually it sets the value correctly, BUT then it returns from the constructor and after this the private instance variable is initialized with "inital value". By removing the assignment, the value of someLocalVariable stays unchanged after returning from ctor.
But there is still something wrong with this solution, because if the compiler options --strictPropertyInitialization and --strictNullChecks are enabled, then the compilation fails.
For me this fact is ok at the moment, but it feels like I am doing something wrong.
New to JavaScript.
Seeking some guidance on how to access the calling class name from a static method defined in the superclass using ES6 classes. I've spent an hour searching, but have not been able to come up with a solution.
A code snippet may help clarify what I am seeking
class SuperClass {
get callingInstanceType() { return this.constructor.name }
static get callingClassType() { return '....help here ...' }
}
class SubClass extends SuperClass { }
let sc = new SubClass()
console.log(sc.callingInstanceType) // correctly prints 'SubClass'
console.log(SubClass.callingClassType) // hoping to print 'SubClass'
As illustrated above, I can easily get the subclass name from a instance. Not quite sure how to access from a static method.
Ideas for the implementation of static get callingClassType() welcomed.
callingClassType is a function (well, a getter in this case, same thing). The value of this inside a function depends on how it is called. If you call a function with foo.bar(), then this inside bar will refer to foo.
Thus if you "call" the function with SubClass.callingClassType, this will refer to SubClass. SubClass is itself a (constructor) function thus you can get its name via the name property.
So your method definition should be
static get callingClassType() { return this.name; }
class SuperClass {
get callingInstanceType() {
return this.constructor.name
}
static get callingClassType() {
return this.name
}
}
class SubClass extends SuperClass {}
let sc = new SubClass()
console.log(sc.callingInstanceType)
console.log(SubClass.callingClassType)
Have a look at the MDN documentation to learn more about this.
Use SuperClass.prototype.constructor.name:
class SuperClass {
get callingInstanceType() { return this.constructor.name }
static get callingClassType() { return SuperClass.prototype.constructor.name; }
}
class SubClass extends SuperClass {}
class SubClass2 extends SuperClass {
static get callingClassType() { return SubClass2.prototype.constructor.name; }
}
console.log(SuperClass.callingClassType); // 'SuperClass'
console.log(SubClass.callingClassType); // 'SuperClass'
console.log(SubClass2.callingClassType); // 'SubClass2'
From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static#Examples:
class Triple {
static triple(n) {
if (n === undefined) {
n = 1;
}
return n * 3;
}
}
class BiggerTriple extends Triple {
static triple(n) {
return super.triple(n) * super.triple(n);
}
}
console.log(Triple.triple()); // 3
console.log(Triple.triple(6)); // 18
var tp = new Triple();
console.log(BiggerTriple.triple(3));
// 81 (not affected by parent's instantiation)
console.log(tp.triple());
// 'tp.triple is not a function'.
Is there any way to determine if a subclass implements a constructor from within a static method (in a base class)?
I'm trying to write a static create method (that acts like the new keyword) that by default works by passing attribute values as a properties object:
class Person extends Class {
greet() { return 'hello from ' + this.name; }
}
var p = Person.create({name: 'world'}; // create a new Person object and set its `name` property to `'world'`
console.log(p.greet()); // => "hello from world"
but hands off to the class' constructor if it has one:
class Person2 extends Class {
constructor(name) {
super();
this.name = name;
}
greet() { return 'hello from ' + this.name; }
}
var p = Person2.create('world');
console.log(p.greet()); // => "hello from world"
I'm stuck at finding out if the subclass defines its own constructor..
class Class {
static create(...args) {
let has_ctor = ?? // true iff the current subclass defines a constructor..
if (has_ctor) {
// let the constructor handle everything
return new this(...args);
} else {
// assume that `args` contains exactly 1 pojo that defines instance variables to be overridden..
var instance = new this();
let props = args[0];
for (let prop in props) instance[prop] = props[prop];
return instance;
}
}
}
is this even possible?
Seems like it would be much easier to do
class Class {
static create(...args) {
// let the constructor handle everything
return new this(...args);
}
constructor(props){
Object.assign(this, props);
}
}
then if things override the constructor, then can choose to pass props to super() or to assign them manually themselves.
Just to answer your original question
Is there a way to discover if a javascript 6 class defines its own constructor?
No, there is not. Every class does have its own constructor, because a "class" basically is just the constructor function.
If a class definition does not include a constructor method, then it is automatically supplied by the language (see ยง14.5.14); either as
constructor(...args){ super (...args);}
if there is a super class or as
constructor(){ }
if there is none. The result is not distinguishable from a class where such a constructor was explicitly declared.