Unable to use property from constructor - javascript

I'm creating two ES js Classes (Person, Teacher)
class Person {
constructor (name = "no name") {
this.name = name
}
Teacher inherit from Person
class Teacher extends Person {
constructor(name, degree){
super(name)
this.degree = degree;
}
}
In the teacher constructor, I have a new property called degree.
when I create a new property called Full name that takes name and degree. Degree shows as undefined. Although when I log object teacher property is there. It looks like a delay issue. But, shouldn't I be able to access property right away?
class Person {
constructor(name = 'no name') {
this.name = name;
}
}
class Teacher extends Person {
constructor(name, degree) {
super(name);
this.degree = degree;
}
fullname = this.degree + this.name;
printFullName() {
console.log(this.fullname);
}
}
let person = new Teacher('Adam', 'MS.');
console.log(person);
person.printFullName(); // undefined Adam
https://repl.it/#adbarani/TrimBrilliantPaintprogram#index.js

This is the behaviour specified in the MDN documentation:
Public instance fields are added with Object.defineProperty() either at construction time in the base class (before the constructor body runs), or just after super() returns in a subclass.
Your code example is in the second case. The order of execution is thus:
Execute super() in case your class is a subclass
Define the public instance fields on this
Execute the rest of the constructor
If you need a work around, then don't define fullname with the field syntax, but assign to this.fullname as part of the constructor function.

Update fullname to a getter to compute the property value when it is accessed:
class Teacher extends Person {
constructor(name, degree) {
super(name);
this.degree = degree;
}
get fullname() {
return this.degree + this.name;
};
printFullName() {
console.log(this.fullname);
}
}
It sounds like you want fullname to be a property, why not set it in the constructor then?
class Teacher extends Person {
constructor(name, degree) {
super(name);
this.degree = degree;
this.fullname = this.degree + this.name;
}
printFullName() {
console.log(this.fullname);
}
}
Otherwise just change printFullName to do the work for you:
printFullName() {
console.log(this.degree + this.nam);
}
Hopefully that helps!

Related

How can I call the method of the great grandfather in Javascript?

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

Extending objects functionalities in JavaScript through prototypes

I'm studying JavaScript autodidactically, I was searching for ways to inherit from objects and extend their functionalities as well...and... wow! it turns out there are several ways to do it.
So there is a popular one which is extending an object through extend and class keywords (to say it in short) of which I put an example of what I saw right underneath. Ok, since I come from C++ and Python languages, this is indeed! very helpful... but I'm aware of this is sugar code to help programmers who come from object-oriented languages feel JavaScript cozier. So!, my goal is to know how to extend objects functionalities without using the aforementioned method since I'm eager to understanding how js works under the hood (at least to nighing considerably to it) and feeling comfortable with it.
Note
I know there are posts here on this topic, but i think those don't meet my needs, considering those which (are very good) dig deep into it are from around 2012.
With class and extend keywords way
REFERENCE: https://www.geeksforgeeks.org/how-to-extend-an-object-in-javascript/
// Declaring class
class Profile {
// Constructor of profile class
constructor(name, age) {
this.name = name;
this.age = age;
}
getName() {
// Method to return name
return this.name;
}
getAge() {
// Method to return age
return this.age;
}
getClass() {
return this;
}
}
// Class Student extends class Profile
class Student extends Profile {
// Each data of class Profile can be
// accessed from student class.
constructor(name, age, languages) {
// Acquiring of attributes of parent class
super(name, age);
this.lang = [...languages];
}
// Method to display all attributes
getDetails() {
console.log("Name : " + this.name);
console.log("Age : " + this.age);
console.log("Languages : " + this.lang);
}
}
// Creating object of child class with passing of values
var student1 = new Student("Ankit Dholakia", 24,
['Java', 'Python', 'PHP', 'JavaScript']);
student1.getDetails();
I tried this... but I'm not comfortable!
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.selfPresentation = function() {
console.log("Hello, my name is " + this.name + "and I'm " + this.age + " years old.");
}
function Worker(name, age, occupation) {
Person.call(this, name, age);
this.occupation = occupation;
}
Worker.prototype = new Person;
Worker.prototype.selfPresentation = function() {
// I think there undoubtedly is a best approach for this...
this.__proto__.__proto__.selfPresentation.call(this);
console.log("I don't breath only, I'm a " + this.occupation);
}
let variable = new Worker("Arturo", 22, "Student");
variable.selfPresentation();
(This is a little aside my goal but..) For inheritance between objects I tried to mimic Object.create method
a = {
field: "field",
method: function() {
console.log("SuperMethod");
}
}
function inheritHimAll(object) {
function helperFunction() {}
helperFunction.prototype = object;
return new helperFunction;
}
b = inheritHimAll(a);
console.log(b.__proto__)
What would be the best approach for extending objects in javascript?
What would be the best approach for extending objects in javascript?
This is quite a subjective question, but I use the class syntax when I can. They are more intuitive, and require less boilerplate code.
However, I think you are more interested in knowing how to do inheritance without the class syntax. Here's what I would change from your example:
Don't create a new instance of the class for prototype. The properties all live in the object, not in the prototype. Instead, use Object.create() to create a new object with the class's prototype. See this answer for more information about this.
Never use __proto__. Instead, call the function from the class's prototype manually or use Object.getPrototypeOf().
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.selfPresentation = function() {
console.log("Hello, my name is " + this.name + "and I'm " + this.age + " years old.");
}
function Worker(name, age, occupation) {
Person.call(this, name, age);
this.occupation = occupation;
}
Worker.prototype = Object.create(Person.prototype);
Worker.prototype.selfPresentation = function() {
Person.prototype.selfPresentation.call(this);
console.log("I don't breath only, I'm a " + this.occupation);
}
let variable = new Worker("Arturo", 22, "Student");
variable.selfPresentation();

Javascript: Using super to call parent prototype function inside child prototype function

I have a question about prototypes and the usage of super in JS.
I have a parent class Person. I have hooked a new toString() function to Person.prototype .
Then, I have a child class Teacher (extends Person). I am trying to override the toString() method on its prototype too, however I would like to reuse the result of the toString() method of its parent.
I attempted to call the toString() method of the super object in the Teacher function, but I get an error saying that super is undefined.
Why is that?
Is it possible to reuse a method of the parent through super in a prototype function of the super's child?
Now, I'm aware that the issue can be solved in another way, but I'm still curious if it's doable in the manner above.
Here's some reference code:
class Person {
name;
email;
constructor(name, email){
this.name = name;
}
}
Person.prototype.toString = function(){
return `name: ${this.name}`
}
class Teacher extends Person{
constructor(name, subject){
super(name);
this.subject = subject;
}
}
Teacher.prototype.toString = function(){
return this.super.toString() + ` subject: ${this.subject}`
}
let teacher = new Teacher("testname", "testSubject");
console.log(teacher.toString());
I don't believe super is available when you define a function on the prototype like that. Instead, you should define your methods within the class and use super.toString. Like this:
class Person {
constructor(name, email) {
this.name = name;
}
toString() {
// you were missing `this` here
return `name: ${this.name}`;
}
}
class Teacher extends Person {
constructor(name, subject) {
super(name);
this.subject = subject;
}
toString() {
return super.toString() + ` subject: ${this.subject}`;
}
}
let teacher = new Teacher("testname", "testSubject");
console.log(teacher.toString());

Is there a way to access superclass variables in subclass with JavaScript?

I was learning JavaScript oops with some sample example when I came across to access superclass methods in subclass which is possible with super keyword
but when I try to access or return a variable of super class it returns undefined or the sub class variable I tried in various way to get variable
I have also gone this Stack Overflow post.
class dad {
constructor(name) {
this.name = name;
}
printname() {
console.log(this.name);
var a = 2;
return a;
}
sendVal() {
console.log(this.name);
var a = 2;
return this.name;
}
}
class son extends dad {
constructor(name) {
super(name);
}
printname() {
console.log(super.printname());
}
printvariable() {
console.log(super.name);
}
getvalue() {
console.log(super.sendVal())
}
}
var o1 = new dad('jackson');
var o2 = new son('jack')
o1.printname()
o2.printname()
o2.printvariable()
o2.getvalue()
When you use super.fieldName to access a field of a parent class, you are actually querying the field name on the prototype of the parent class.
So you might believe calling super(name); from the Son constructor sets the name in the prototype of the parent class, but it is not so, it actually sets the name property inherited by the Son class which you can access by using this.name.
So I modified your example code and shown how to actually get a value by calling super.fieldName. In the example I added a property age in the prototype of the Dad class and set its value to 50, now in the Son class printvariable() will correctly call the super.age by referring the prototype of the Dad class.
You can actually see it in action if you use babel to transpile it to ES2015, after all classes in JavaScript are actually syntactic sugar.
class Dad {
constructor(name) {
this.name = name;
Dad.prototype.age = 50; //adding property to prototype
}
printname() {
console.log(this.name);
var a = 2;
return a;
}
sendVal() {
console.log(this.name);
var a = 2;
return this.name;
}
}
class Son extends Dad {
constructor(name) {
super(name);
}
printname() {
console.log(super.printname());
}
printvariable() {
console.log(`super.name will be undefined, as not present in prototype of the Dad class: ${super.name}`);
console.log(`super.age will have a value of 50, present in the prototype of the Dad class: ${super.age}`);
console.log(`this.name will be jack, as it is set from the constructor of the Son class: ${this.name}`);
}
getvalue() {
console.log(super.sendVal());
}
}
var o1 = new Dad('jackson');
var o2 = new Son('jack')
o1.printname();
o2.printname();
o2.printvariable();
o2.getvalue();

How does property lookups after calling super() in subclass actually work

I've a simple example from MDN.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Dog extends Animal {
constructor(name) {
super(name); // call the super class constructor and pass in the name parameter
}
speak() {
console.log(this.name + ' barks.');
}
}
let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.
Now, in subclass Dog how does this.name works under the hood. Since this refers to Dog class instance and name is not something which exists on Dog instance. So to access that we use super call which invokes parent's constructor. I get that it looks up.
But can someone please explain via the prototype mechanism (I'm comfortable in understanding the prototype lookup and chaining mechanism).
I'm sure deep down it will boil down to that but not clear about intermediate steps in between. Thanks!
this refers to Dog class
No, this refers to the instantiated object. The instantiated object has an internal prototype of Dog.prototype, and Dog.prototype has an internal prototype of Animal.prototype.
Since this refers directly to the instantiated object (in both constructors, and in all of the methods),
this.name = name;
puts the name property directly on that object, so it's completely fine to reference d.name, or, inside one of the methods, this.name:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Dog extends Animal {
constructor(name) {
super(name); // call the super class constructor and pass in the name parameter
}
speak() {
console.log(this.name + ' barks.');
}
}
const d = new Dog('Mitzie');
const dProto = Object.getPrototypeOf(d);
const secondProto = Object.getPrototypeOf(dProto);
console.log(dProto === Dog.prototype);
console.log(secondProto === Animal.prototype);
console.log(d.hasOwnProperty('name'));
Actually, what I wanted to ask was under the hood. So, here's the answer based on #Jai's pointer in comments that I was looking for.
I ran the class based code through es5compiler or any compiler and got this conversion
var Dog = /** #class */ (function (_super) {
__extends(Dog, _super);
function Dog(name) {
return _super.call(this, name) || this;
}
Dog.prototype.speak = function () {
console.log(this.name + ' barks.');
};
return Dog;
}(Animal));
So basically
return _super.call(this, name) inside Dog function explains the confusion of this reference inside speak method of class Dog. It changes the context through call()

Categories

Resources