FAQ: Classes - Introduction to Classes

This community-built FAQ covers the “Introduction to Classes” exercise from the lesson “Classes”.

Paths and Courses
This exercise can be found in the following Codecademy content:

Web Development

Introduction To JavaScript

FAQs on the exercise Introduction to Classes

There are currently no frequently asked questions associated with this exercise – that’s where you come in! You can contribute to this section by offering your own questions, answers, or clarifications on this exercise. Ask or answer a question by clicking reply (reply) below.

If you’ve had an “aha” moment about the concepts, formatting, syntax, or anything else with this exercise, consider sharing those insights! Teaching others and answering their questions is one of the best ways to learn and stay sharp.

Join the Discussion. Help a fellow learner on their journey.

Ask or answer a question about this exercise by clicking reply (reply) below!

Agree with a comment or answer? Like (like) to up-vote the contribution!

Need broader help or resources? Head here.

Looking for motivation to keep learning? Join our wider discussions.

Learn more about how to use this guide.

Found a bug? Report it!

Have a question about your account or billing? Reach out to our customer support team!

None of the above? Find out where to ask other questions here!

what is difference between factory function and creating a class for creating objects …? why to use class/factory function…?

15 Likes

Where is the key ‘age’ in the object halley?

5 Likes

Good question actually

There is no age key in the halley object. I think they are just saying it as an example in the text

Following is an article from a couple years ago that keeps it simple, but does a good job of covering all the bases. Follow up study and experimenting is up to the reader.

In Depth - JavaScript Factory Functions

This link was posted here a couple of years ago in the public interest but the article is still there and just as valid and meaningful today as it was then.

Hope it opens some doors in your mind. Don’t be afraid to bring up any other question around this topic. We do still need to extrapolate the differences between in the original question.


Continuing…

Let’s look at something simple and compare…

foo = (name, city) => {
  return {
    name,
    city
  }
};
wee = foo('Wee Gillis', 'St. William')
wee.name    // Wee Gillis
wee.city    // St. William
wee instanceof foo

Uncaught TypeError: Function has non-object prototype ‘undefined’ in instanceof check

wee instanceof Object

true

Now let’s look a class object instance…

class Foo {
  constructor (name, city) {
    name,
    city
  }
}

 > gillis = new Foo('Wee Gillis', 'St. William')
<- Foo {}

As I interpret this, it tells us that the constructor does not support destructuring. Mind, this is not an expert view, only what we observe.

class Foo {
  constructor (name, city) {
    this.name = name;
    this.city = city;
  }
}

 > gillis = new Foo('Wee Gillis', 'St. William')
<- Foo {name: "Wee Gillis", city: "St. William"}
 > gillis instanceof Foo
<- true

Clearly, if we wish to identify objects as being related to one another by their similarity and purpose object literals do not offer the same distinction as class instances. If we wish to give our object literals more functionality we have to modify the Object.prototype which is never a good idea.

If we wish to add functionality to a class, and have it reach across all instances, instantly, then we have the constructor prototype to work with and it has no bearing on the Object prototype. We’re in safe territory.

This is not necessarily an advantage in a plain sense. Our overall design and motivation is at the core of what functionality, especially dynamic functionality we will need in any one session. See it only as a difference.

 > Foo.prototype.getName = function() { return this.name }
<- ƒ () { return this.name }
 > gillis.getName()
<- "Wee Gillis"
 > Foo.prototype.getCity = function() { return this.city }
<- ƒ () { return this.city }
 > gillis.getCity()
<- "St. William"

A factory object does not have this, on the fly functionality, but what of it? If we don’t need it, then we are leaning the right way in terms of simplicity.

We may conclude that a factory object is not a class and is not a constructor. It is a plain object with only Object.prototype to inherit from. We do not invoke an instance with new, but only assignment. They are very session oriented which likely makes them easy to work with.

Remember, factory objects are similar to each other if coming from the same factory function, but they have no way of knowing their similarity since they only have Object.prototype in their inheritence chain. Everything is an object so that makes them pretty generic. Our program logic needs to draw the correlation between these objects.

Here is where a data structure comes in to help organize loosely created object instances returned from the same factory. Put them all in the same array.

 > foos = []
<- []
 > foos.push(foo('Wee Gillis', 'St. William'))
<- 1
 > foos.push(foo('MTF', 'Edmonton'))
<- 2
 > foos
<- (2) [{…}, {…}]
   0: {name: "Wee Gillis", city: "St. William"}
   1: {name: "MTF", city: "Edmonton"}
   length: 2
   __proto__: Array(0)

 > foos.map((x) => Object.values(x))
<- (2) [Array(2), Array(2)]
     0: (2) ["Wee Gillis", "St. William"]
     1: (2) ["MTF", "Edmonton"]
     length: 2
     __proto__: Array(0)
2 Likes

Is this the explanation on what’s the difference between a Factory function and a class? it seems that the difference is that a FF just don’t use the constructor or class declaration but both do the same thing

1 Like

I would not so much as call it an explanation as an exploration, and patchy at best. It’s a path we can go down to explore a number of things, many of which are slightly over my head but I don’t mind being in on the conversation. Please do share your own discoveries on this topic.


Late edit, off topic

A side project would be to refactor the Build a Library project to use only factory functions. Better now, than down the road when it’s in production. It would give us a template, or sample at least of what advantages may be lost or gained, and possibly even how to mitigate any loss in functionality.

Eg.

const catalog = (media, title) => {
  return {
    _media: media,
    _title: title,
    get media() {
      return this._media;
    },
    get title() {
      return this._title;
    }
  }
}
aon = catalog('record', 'Art of Noise')
console.log(aon.media)
console.log(aon.title)

record
Art of Noise

2 Likes

Hi,
The getters in the first example in the explanation part (with the object Halley) don’t make sense to me.
I understand the general concept of getters, but i dont understand the logic of getting name and returning to _name.
Thank you…

1 Like

This is known as the backing variable, and is necessary to prevent circular references.

1 Like

I just noticed that there is no comma between getters and other methods within a class, unlike within an object. So I looked it up. According to MDN Classes are in fact “special functions”. So far it feels strange.

1 Like

Great that you noticed the difference and followed up on your hunch. Classes could almost be considered a blueprint of objects, but not a set, where an object is a compilation of attributes that is comparable to a set.

2 Likes

The exercise only shows 1 example, I want to know how it would look like if we had lets say 3 or 4 dog names(With class and Without class).

Hello, @muaadahmed7090689531.

Once you’ve completed the exercise, you can go back and add as many instances of Dog as you like. Add more methods too, if you want to do some experimenting.

More names means more instances.

class OurPets {
  constructor(family, breed, name, age) {
    this.family = family;
    this.breed = breed;
    this.name = name;
    this.age = age;
  }
}
 > rex = new OurPets('dog', 'labrador', 'Rex', 6)
<- OurPets {family: "dog", breed: "labrador", name: "Rex", age: 6}
 > lassie = new OurPets('dog', 'collie', 'Lassie', 9)
<- OurPets {family: "dog", breed: "collie", name: "Lassie", age: 9}
 > tigger = new OurPets('cat', 'orange tabby', 'Tigger', 12)
<- OurPets {family: "cat", breed: "orange tabby", name: "Tigger", age: 12}
 > polly = new OurPets('bird', 'parrot', 'Polly', 10)
<- OurPets {family: "bird", breed: "parrot", name: "Polly", age: 10}

I have some problem related this topic , i don’t understand that
incrementBehavior(){
this._behavior++;}

what it can do in our code ??

We can assume from your code that there is a, _behavior property that has a number for a value. The above method is used to increment that number (that is, add 1 to it).

In JavaScript we have two such operators. One for incrementing, and one for decrementing.

--
++

It is an in-place operation that happens immediately. We see it in for loops, a lot.

for (let i = 0; i < 10; i++) {

}

where i starts with the initial value of zero, then goes up by 1 on each iteration of the loop. The loop stops when i reaches 10.

1 Like

HI ,
I really do not understand this classes mean and how to use in javascript,
Is there any very simple example to learn from ???

class Dog {
  constructor(name) {
    this._name = name;
    this._behavior = 0;
  }

  get name() {
    return this._name;
  }
  get behavior() {
    return this._behavior;
  }   

  incrementBehavior() {
    this._behavior ++;
  }
}
const halley = new Dog('Halley');
console.log(halley.name); // Print name value to console
console.log(halley.behavior); // Print behavior value to console
halley.incrementBehavior(); // Add one to behavior
console.log(halley.name); // Print name value to console
console.log(halley.behavior); // Print behavior value to console

That’s needlessly confusing. They should change it.

1 Like