I try to use the speak method also to re use with the Zebra class with composition.
SO I have it like this:
class Animal {
constructor(name, age) {
this.name = name;
this.age = age;
}
speak() {
return `my name is: ${this.name} and I am ${this.age} old`;
}
}
class Zebra {
constructor(Animal) {
this.animal = Animal();
}
}
let animal = new Animal("hello", 99);
let zebra = new Zebra();
console.log(zebra.speak());
also composition!!:
class Person {
String Title;
String Name;
Int Age;
public Person(String title, String name, String age) {
this.Title = title;
this.Name = name;
this.Age = age;
}
}
class Employee {
Int Salary;
private Person person;
public Employee(Person p, Int salary) {
this.person = p;
this.Salary = salary;
}
}
Person johnny = new Person ("Mr.", "John", 25);
Employee john = new Employee (johnny, 50000);
I don't recommend to use composition in this case. This is a use-case for inheritance. But academic questions also deserve an answer.
Either use the animal property to call speak:
class Animal {
constructor(name, age) {
this.name = name;
this.age = age;
}
speak() {
return `my name is: ${this.name} and I am ${this.age} old`;
}
}
class Zebra {
constructor(animal) {
this.animal = animal;
}
}
let animal = new Animal("hello", 99);
let zebra = new Zebra(animal);
console.log(zebra.animal.speak());
or add a speak method to Zebra (this is a duplicate of another answer by accident. I didn't see it because it doesn't contain a runnable snippet):
class Animal {
constructor(name, age) {
this.name = name;
this.age = age;
}
speak() {
return `my name is: ${this.name} and I am ${this.age} old`;
}
}
class Zebra {
constructor(animal) {
this.animal = animal;
}
speak() {
return this.animal.speak();
}
}
let animal = new Animal("hello", 99);
let zebra = new Zebra(animal);
console.log(zebra.speak());
This would be more of a thing you are looking for
const animal = {
age: 10,
name: 'hello',
speak() {
return `my name is: ${this.name} and I am ${this.age} old`
}
}
const zebra = {
...animal,
age: 100,
name: 'zebra'
}
console.log(zebra.speak())
This is a simple delegation -
class Zebra {
constructor(animal) {
this.Animal = animal; // animal = Animal
}
speak() {
return this.Animal.speak();
}
}
You can also just use functions instead of new classes -
class Zebra {
constructor(speakFunctionality) {
this.speak = speakFunctionality;
}
}
let zebra = new Zebra((name,age) => { return `my name is: ${this.name} and I am ${this.age} old`; });
zebra.speak();
The first approach doesn't use composition in the best possible way - because when you want to reimplement or add another implementation you'll need to inherit Animal class or provide a type with speak() method.
When doing something like this ask yourself "How do I add a new behavior" - Like you need to implement a Duck how would you do it.
The second approach (With functions) is better because you don't need to provide new classes but create functions - which are easier to manipulate in JS.
This is usually called Strategy pattern where you inject a behavior through ctor or a function.
The example you provided , where you reimplement "Speak" is best suited for Inheritance rather than Composition.
A good example for composition would be a Car with Engine and different parts like Wheels.
class Car {
constructor(engine){
this.Engine = engine;
}
}
Related
Is there a way to declare a function inside class?
If yes, I'm trying to declare function age() inside the class, but i think it is not possible on JavaScript or maybe I'm wrong.
I do not want to put it outside the class because the code looks more organized like this. What are the options available?
My code is below.
class Animal {
constructor(name) {
this.name = name;
}
cat() {
console.log(`Meow! It is cat and his name is ${this.name}`);
console.log(age('cat'));
}
dog() {
console.log(`Au! It is dog and his name is ${this.name}`);
console.log(age('dog'));
}
function age(animal){
if(animal=='cat') return 7;
if(animal=='dog') return 5;
}
}
const fluffy = new Animal('Fluffy');
fluffy.cat();
const billy = new Animal('billy');
billy.dog();
You've already declared functions inside of the class, just do the same for age. To access it, you need to use this.age since JavaScript doesn't look for class instance variables/functions by default.
class Animal {
constructor(name) {
this.name = name;
}
cat() {
console.log(`Meow! It is cat and his name is ${this.name}`);
console.log(this.age('cat'));
}
dog() {
console.log(`Au! It is dog and his name is ${this.name}`);
console.log(this.age('dog'));
}
age(animal) {
if (animal == 'cat') return 7;
if (animal == 'dog') return 5;
}
}
const fluffy = new Animal('Fluffy');
fluffy.cat();
const billy = new Animal('billy');
billy.dog();
As others already said cat and dog are already functions of Animal (member functions).
If you don't want that the age function is a member function (belongs to an instance of Animal) you can make it static:
class Animal {
constructor(name) {
this.name = name;
}
cat() {
console.log(`Meow! It is cat and his name is ${this.name}`);
console.log(Animal.age('cat'));
}
dog() {
console.log(`Au! It is dog and his name is ${this.name}`);
console.log(Animal.age('dog'));
}
static age(animal){
if(animal=='cat') return 7;
if(animal=='dog') return 5;
}
}
const fluffy = new Animal('Fluffy');
fluffy.cat();
const billy = new Animal('billy');
billy.dog();
If you don't want to make it accessible outside of Animal than make it private:
class Animal {
constructor(name) {
this.name = name;
}
cat() {
console.log(`Meow! It is cat and his name is ${this.name}`);
console.log(Animal.#age('cat'));
}
dog() {
console.log(`Au! It is dog and his name is ${this.name}`);
console.log(Animal.#age('dog'));
}
static #age(animal){
if(animal=='cat') return 7;
if(animal=='dog') return 5;
}
}
const fluffy = new Animal('Fluffy');
fluffy.cat();
const billy = new Animal('billy');
billy.dog();
However having a private static function is rarely useful. The intent of a static method is that it logically belongs to the class but performs a task that does not require an instance of that class.
Hi Jessica You can put it as a method if you want.
But I think anyway in this case you should have a class for cat and another one for dog.
Or pass in the constructor the age but it will mean that the age will not be related to what is the animal.
Long story short you can decide or to create a class for each or to create a method inside the class.
You can create a function in a class, but the correct syntax requires you to omit the 'function' keyword. Also use this keyword to refer to the current object.
class Animal {
constructor(name) {
this.name = name;
}
cat() {
console.log(`Meow! It is cat and his name is ${this.name}`);
console.log(this.age('cat'));
}
dog() {
console.log(`Au! It is dog and his name is ${this.name}`);
console.log(this.age('dog'));
}
age(animal){
if(animal=='cat') return 7;
if(animal=='dog') return 5;
}
}
const fluffy = new Animal('Fluffy');
fluffy.cat();
const billy = new Animal('billy');
billy.dog();
well I can come up with 3 way to define some functionality in a class
number one: method ,it is the common one that you are likely to see in class based codes
class Animal{
//rest of class
age(){
//your function goes here
}
}
you can latter access it with an instance of class
const cat = new Animal() cat.age()
number two: static ,it is somewhat different because it belong to class itself
class Animal{
//rest of class
static age(){
//your function goes here
}
}
in this case you don't need to create an instance of class
Animal.age()
and lastly: treating your function as property it is not different from using method but I would recommend method if you want to use this functionality often there are minor differences in** memory usage**
syntax goes like this
class Animal {
constructor(name) {
this.age= ()=>{//your function}
}}
use age like this
const cat = Animal()
, {age} = cat
age()
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!
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();
I have a function constructor defined this way:
var Person = function (name, yearOfBirth, job) {
this.name = name;
this.yearOfBirth = yearOfBirth;
this.job = job;
}
Person.prototype.calculateAge = function () {
console.log(2016 - this.yearOfBirth);
};
Now I also have another function constructor called Teacher which I've defined this way:
var Teacher = function (name, yearOfBirth, subject) {
Person.call(this, name, yearOfBirth, "teacher");
this.subject = subject;
}
Now I create a new object called roySir this way:
var roySir = new Teacher("Roy", 1960, "English");
However when I try to do
roySir.calculateAge() I get an error saying that
"roySir.calculateAge is not a function"
How come the calculateAge function is not inherited here?
Another question I have is when I check:
roySir.hasOwnProperty("name") // true
Why is this true here? Isn't name a property of the parent class rather than an own property?
You should ensure that Teacher's prototype inherits from Person's prototype. Simply calling Person with a Teacher won't let Teacher inherit from Person's prototype methods:
var Person = function(name, yearOfBirth, job) {
this.name = name;
this.yearOfBirth = yearOfBirth;
this.job = job;
}
Person.prototype.calculateAge = function() {
console.log(2016 - this.yearOfBirth);
};
var Teacher = function(name, yearOfBirth, subject) {
Person.call(this, name, yearOfBirth, "teacher");
this.subject = subject;
}
Teacher.prototype = Object.create(Person.prototype);
var roySir = new Teacher("Roy", 1960, "English");
roySir.calculateAge();
You need the Object.create rather than Teacher.prototype = Person.prototype there so that mutations to Teacher.prototype won't undesirably change Persons that aren't Teachers - for example, if you gave Teacher.prototype a teachesClass method, you would want only Teachers to have access to that, but you wouldn't want a generic Person to have that method.
Alternatively, use ES6 and extends, which is more readable:
class Person {
constructor(name, yearOfBirth, job) {
this.name = name;
this.yearOfBirth = yearOfBirth;
this.job = job;
}
calculateAge() {
console.log(2016 - this.yearOfBirth);
}
}
class Teacher extends Person {
constructor(name, yearOfBirth, subject) {
super(...[name, yearOfBirth, subject, 'teacher']);
}
}
var roySir = new Teacher("Roy", 1960, "English");
roySir.calculateAge();
As for the name property, it's assigned to the object itself with this.name = name; - when a constructor is called, like with Person.call(this, ...), the this in the other constructor still refers directly to the object being created in the calling code - that's what call does, the first argument passed to it will be a direct reference to the this used in the other function.
The prototype chain looks like:
roySir { name, yearOfBirth, job }
above inherits from Teacher.prototype (empty)
above inherits from Person.prototype { calculateAge }
class Name{
constructor(name)
{
this.name = name
}
}
function greet()
{
return "Hello World"
}
let Max = Reflect.construct(Name,["Maxi"],greet);
console.log(Max.__proto__ == greet.prototype); //true
Why it is necessary override object prototype
I believe this is one way for you to achieve what you would like to do with the classes of ES6;
class Name{
constructor(name)
{
this.name = name;
}
greet(n){return "Hello " + n;}
}
var Max = new Name("Maxi");
console.log(Max.greet("John"));