JavaScript function from class extension not recognized - javascript

I'm playing around with classes ES6 and encountered behaviour with below code.
Error I'm getting is bob.personName is not a function.
Both class and it extension has constructor defined but still I can't get it working. I added comments under lines that I think might be the issue. Thanks for help!
class Person {
constructor(canSpeak) {
this.canSpeak = true;
}
}
class Hello extends Person {
constructor(name) {
this.name = name;
}
personName() { //am I missing a parameter?
if (this.canSpeak) {
return `Name is: ${this.name}, can speak? ${this.canSpeak}`;
}
};
};
const bob = new Person('Bob'); //should I call Hello extension instead?
console.log(bob.personName());

Since the method exists on Hello.prototype, not on Person.prototype, you need the instance to be of a Hello.
You also can't reference this until calling super inside a subclass's constructor, so do that before assigning to this.name:
class Person {
constructor(canSpeak) {
this.canSpeak = true;
}
}
class Hello extends Person {
constructor(name) {
super();
this.name = name;
}
personName() { //am I missing a parameter?
if (this.canSpeak) {
return `Name is: ${this.name}, can speak? ${this.canSpeak}`;
}
};
};
const bob = new Hello('Bob'); //should I call Hello extension instead?
console.log(bob.personName());

Related

Using method from super class returns undefined after result

I am playing around with classes and I noticed that after checking status I am seeing the console log, but afterward I am seeing undefined. Can anyone explain how to get around this and why is this happening?
class Test {
constructor(name) {
this.name = name;
}
status() {
console.log("test")
}
}
class Test1 extends Test {
constructor(name) {
super(name);
}
checkStatus() {
super.status();
}
}
const b = new Test1("Test")
console.log(b.checkStatus())
What does Console.log do?
The method console.log does not return a value. This seems to be a common misunderstanding, people seem to assume that it will return what is printed to the log.
However, even if that was an assumption, status() does not have an explicit return, so the value is undefined.
Functions vs arrow functions
Here another misunderstanding creeps in, which is the difference between regular functions and arrow functions. Arrow functions have a convenience which is that if the function body resolves to a value, its taken as the return value. Consider:
function foo() {
return 'foo'
}
console.log(foo()) // foo() returns 'foo', so the log shows 'foo'
const bar = () => 'bar'
console.log(bar()) // bar() returns 'bar', so the log shows 'bar'
const baz = () => console.log('baz')
console.log(baz()) // baz() returns undefined, so the log shows 'baz' and 'undefined'
Use of super
checkStatus() {
super.status();
}
You use super here for no (good) reason. status() has been inherited from class Test, and can be called with this.status(). You would only need to use super.status() if you were providing an override in Test1 and needing to call the parent class implementation.
I suspect that this is actually what you intended, but because of the lack of return statements, you were trying to understand what was being called where and got sidetracked.
Revised Code
Here I've renamed the classes to make things a little clearer.
TestBase provides our base class functionality.
TestOverride provides an override implementation of status that prepends its own name to the value returned by TestBase.status, called via super (this.super() here would create an infinite loop).
TestNoOverride does not add anything to TestBase, so the return value is just as per TestBase (but note that it is using the name passed into the constructor.
The most important lesson here is that YOU MUST provide an explicit return value if you expect to be able to assign (or log) the return value from a function. The exception to this is if the function is an arrow function with a simple statement as the function body, in which case the arrow function takes that value as the (implicit) return.
class TestBase {
constructor(name) {
this.name = name;
}
status() {
return "TestBase " + this.name
}
}
class TestOverride extends TestBase {
constructor(name) {
super(name);
}
status() {
return "TestOverride " + super.status();
}
}
class TestNoOverride extends TestBase {
constructor(name) {
super(name);
}
}
const a = new TestBase("A")
console.log(a.status())
const b = new TestOverride("B")
console.log(b.status())
const c = new TestNoOverride("C")
console.log(c.status())
You are logging the value returned by b.checkStatus(), which is undefined as the function does not return a value. Most likely you do not want this return value to be logged.
class Test {
constructor(name) {
this.name = name;
}
status() {
console.log("test")
}
}
class Test1 extends Test {
constructor(name) {
super(name);
}
checkStatus() {
super.status();
}
}
const b = new Test1("Test")
b.checkStatus()
Consider this line:
console.log(b.checkStatus())
This runs checkStatus() in the Test1 class, which runs status() in Test. Well, consider status():
console.log("test")
Ok, "test" is printed to the console. Now, as there is no return function, undefined is implicitly returned. checkStatus() therefore returns this value, undefined. You then log this with console.log(b.checkStatus()), printing undefined.
If you look carefully, you have two console.log()s in your program. Hence the two outputs, the second being undefined.
This happens because your checkStatus method does not return anything.
It's the same as if you were doing
function hello(){
console.log('hello')
}
console.log(hello())
If you want your function to return something you can return something in the parent method and in the checkStatus method
class Test {
constructor(name) {
this.name = name;
}
status() {
return "test"
}
}
class Test1 extends Test {
constructor(name) {
super(name);
}
checkStatus() {
return super.status();
}
}
const b = new Test1("Test")
console.log(b.checkStatus())

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

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());

Javascript: Recalling function inside a class

I am relatively new to the programming and I have a mere basic question which have been bothering me (I just can't recall if my instructor told me about this or not)
Is this Same as
class Person extends Human {
constructor() { //how to avoid (1)
super();
this.gender = male;
this.name = "shivom"; //we add super since we are using constructor
}
printMyname() {
console.log(this.name);
}
}
this
class Person extends Human {
constructor() { //how to avoid (1)
super();
this.gender = male;
this.name = "shivom"; //we add super since we are using constructor
}
function printMyname() {
console.log(this.name);
}
}
If not, what is the difference between the both? and If anyone can suggest me any related article to read more? (notice the use of function for printMyName in later one)
I think you can refeer to these links for more information on classes in ES6
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
https://www.reddit.com/r/learnjavascript/comments/6jzx1j/why_no_function_keywords_inside_classes/
you will get Uncaught SyntaxError: Unexpected identifier in second one.You can only use function like code below in class:
class Person extends Human {
constructor() {
// Function code
}
someFunction() {
// Function code
}
static sayHi() {
// Function code
}
}
You should read docs before code

Inline binding of external function to class method

Let's say I have a function that returns a function like this:
function createGreeter(logger) {
return function greet(greeting) {
logger.log(greeting + ', ' + this.name);
}
}
And a class
class Person {
constructor(name) {this.name = name;}
}
If I want to assign a greet method to the Person class that uses the console as the logger, I can think of several ways:
1.
class Person {
constructor(name) {this.name = name;}
greet(greeting) {
return createGreeter(console).call(this, greeting);
}
}
2.
class Person {
constructor(name) {this.name = name;}
}
Person.prototype.greet = createGreeter(console);
However, I think both of these are somewhat ugly; 1) creates an, essentially, unnecessary wrapper method that simply binds this and calls the function, and 2) modifies the prototype outside of the class body which in my opinion makes the class API less clear.
Is there no clearer/shorter syntax for inline assignment and binding of an external function to a class method. I'm thinking something like:
class Person {
constructor(name) {this.name = name;}
greet: createGreeter(console)
}
...which resembles how you would be able to assign a function in an object literal. But this doesn't work, obviously. Is there something similar (now, or upcoming)?
Also, I'm wondering about the memory consumption and/or performance aspects of returning a closure as in 1) if the returned function is large. Every time the greet method is called on a Person object, a new function object will be created even though we always want to pass the same parameters (console) to it. So yet another approach could be to declare const consoleGreeter = createGreeter(console) before the class definition and implement greet as return consoleGreeter.call(this, greeting), but would it be worth it?
class Person {
constructor(name) {this.name = name;}
}
Person.prototype.greet = createGreeter(console);
is the proper way to do this, unless there are other concerns (it will have problems in TypeScript).
This can be also done with class fields, which are stage 3 proposal and will likely land in ES2018:
class Person {
greet = createGreeter(console);
}
Which is a shortcut for
class Person {
constructor() {
this.greet = createGreeter(console);
}
}
First snippet evaluates createGreeter(console) once and assigns the method to class prototype. Second snippet evaluates it every time the class is instantiated and assigns the method to class instance, which is less effective.
Ok, so here is an alternative to bind external method to class
class Person {
constructor(name) {this.name = name;}
get greet() { return createGreeter(console) }
}
Just checked, this is also working fine.
This would achieve the same effect #1, since the wrapper is invoked each time the method is accessed. If that's okay with you to improve readability...
function createGreeter(logger) {
return function greet(greeting) {
logger.log(`${greeting}, ${this.name}`);
};
}
class Person {
constructor(name) {
this.name = name;
}
get greet() {
return createGreeter(console);
}
}
let person = new Person('Patrick');
person.greet('Hello');

Categories

Resources