Reputation: 11
While doing an exercise, I used a Class in my code and it worked fine, but the thing is that they told me I couldn't use class because it's not covered by the JavaScript online prep course. I'm so confused and when trying to re-write the constructor object without grouping it in a class it just doesn't work!
The exercise is the following:
/*
Write your code for this exercise in this file beneath this long comment. Please
be certain to use only syntax and techniques covered in the assigned
freeCodeCamp courses.
1. Write a function named createMovie that expects to receive three arguments:
title, duration, and quote. This function should return an object. The object it
returns should have properties that are also named title, duration, and
quote. The values assigned to these properties should be the values that are
passed to the function. Additionally, the object that createMovie returns should
have two methods:
isLongerThan - a function that accepts one movie object as a parameter and
returns true if the movie is longer than the one that is passed to it as
an argument and false otherwise.
logQuote - a function that logs the value of the movie object's quote
property to the console.
2. Create a variable named movies and assign to it an array. This array should
contain six objects that are created by calling the createMovie function. The
values you should pass to the createMovie function to create these objects are:
title | duration | line
----------------------------------------------------------------------------
Star Wars | 121 | If there's a bright center to the universe,
| | you're on the planet that it's farthest from.
| |
Pulp Fiction | 154 | Do you know what they call a Quarter Pounder
| | with Cheese in France?
| |
Dirty Dancing | 100 | Nobody puts Baby in a corner.
| |
Forrest Gump | 142 | Life is like a box of chocolates.
| |
The Wizard of Oz | 101 | Lions and tigers and bears, oh my!
| |
Cabaret | 124 | Life is a cabaret, old chum, so come to the
| | cabaret.
3. Write the following two functions, both of which use the movies array to
determine what to return.
getMovieByTitle - this function expects a string as a parameter and
returns the object in the movies array whose title property is equal to
the string that is passed to it (if there is one).
getAverageDuration - this function returns the average duration of all the
movies in the array.
You can test your code by opening index.html in Chrome and using the console
(see http://jsforcats.com/ for instructions on using the console). After you
correct any errors you see when you open the console, you can run commands such
as those below and verify the output.
var starWars = getMovieByTitle('Star Wars');
var pulpFiction = getMovieByTitle('Pulp Fiction');
pulpFiction.isLongerThan(starWars);
pulpFiction.logQuote();
getAverageDuration();
*/
This is the code I've written (with the help of a friend):
class Movie{
constructor(title, duration, quote){
this.title = title;
this.duration = duration;
this.quote = quote;
}
isLongerThan(movie){
if (movie.duration > this.duration){
return true
}
else{
return false
}
}
logQuote(movie){
console.log(movie.quote);
}
}
function createMovie(title, duration, quote){
let movie = new Movie(title, duration, quote);
return movie;
}
let movies = [];
let starWars = createMovie("Star Wars", 121, "If there's a bright center to the universe, you're on the planet that it's farthest from.");
let pulpFiction = createMovie("Pulp Fiction", 154, "Do you know what they call a Quarter Pounder with Cheese in France?");
let dirtyDancing = createMovie("Dirty Dancing", 100, "Nobody puts Baby in a corner.");
let forrestGump = createMovie("Forrest Gump", 142, "Life is like a box of chocolates.");
let theWizardOfOz = createMovie("The Wizard of Oz", 101, "Lions and tigers and bears, oh my!");
let cabaret = createMovie("Cabaret", 124, "Life is a cabaret, old chum, so come to the cabaret.");
movies.push(starWars, pulpFiction, dirtyDancing, forrestGump, theWizardOfOz, cabaret);
function getMovieByTitle(movie){
for (i = 0; i < movies.length; i++){
if (movies[i].title = movie){
return movies[i].title;
}
else {
return false
}
}
}
function getAverageDuration(){
let total = 0;
let length = movies.length;
for (i = 0; i < movies.length; i++){
total += movies[i].duration;
}
return total / length;
}
How can I group the isLongerThan
and getAverageDuration
methods inside the object?
My mind is just blocked...
Thank you!
Upvotes: 1
Views: 510
Reputation: 9835
The exercise requires you to create a Factory function, without relying on prototype
or class
.
Here more about Prototypes & Prototypical Inheritance. Some theory on Wikipedia.
Note the other answer from @Regs Isabelo Jr.: it is a valid solution to the exercise; as he mentioned it is a simpler solution for "grouping" the methods into one place (instead of the use of class
). Try to understand that first!.
His answer defines a Factory function that creates and returns a simple object that owns properties and methods.
That way, without having a prototype
you re-define the methods on each created instance of the object. So each object consumes more memory and is unrelated from the other sibling objects. Think about an orphanage and how each child might be similar but coming from different parents.
This is instead how I would write it:
function createMovie(title, duration, quote) {
console.log('Creating a new instance of Movie');
return new Movie(title, duration, quote);
}
// this is the object (not class) constructor
function Movie(title, duration, quote){
this.title = title;
this.duration = duration;
this.quote = quote;
}
// these are the definitions for the object (not class) methods
Movie.prototype.isLongerThan = function(movie) {
return movie.duration > this.duration;
};
Movie.prototype.logQuote = function() {
console.log(this.quote);
};
const myFavoriteMovie = new Movie(
'The Thin Red Line',
2.90,
[
"Love. Where does it come from? Who lit this flame in us? No war can put it out, conquer it. I was a prisoner. You set me free.",
"Property. The whole fucking thing's about property."
]
);
prototype
As you can see from my example, the solution is more complex. It implies the understanding of prototype
rather than of class
. My factory function is just a simple proxy to creating a new instance of Movie
.
I personally prefer defining as much methods as possible on the object's prototype, because later on this allows a more Object-Oriented approach and expectations (Parent/Children), when needing to implement complex inheritance between objects.
Using the prototype
is more similar to the OOP concept of class; and its inheritance mechanism allows to spare memory (since what's on the prototype is being defined just once in memory and then it is retrieved by the inheriting/children objects, avoiding duplication). Think about parents with children that have some similar/shared characteristics inherited by the bloodline.
Main differences:
new FoobarPrototypedClass()
) object instances all referring to the same definition; hence making the instances related to each other (via the parent/prototype definition). Changes to the parent's prototype
will affect all the children (since the prototype is shared).class
& extends
The class
construct that you used is just a (recent) replacement of the above operations, but added in JS to be understood by people used to OOP concepts.
I usually suggest to avoid using class
because it is a false promise, and it doesn't behave as expected when you start to have more complex cases.
Using class
is a palliative; it's like a painkiller: it avoids the pain but one day it will bite you back.
A more consistent approach is to put the time to understand how prototypes and prototype-chain work. Javascript requires you to understand the concepts at the base of it, in order to be used properly.
It is not complicated, but rather low-level and a little unintuitive (especially if one comes from Object-Oriented mindset). For achieving inheritance one needs to memorize the pattern, because it isn't achieved in a single instruction like the extends
of other languages.
I would suggest to study further:
Object.create(Movie.prototype)
and new Movie()
Child.prototype = new Parent(); Child.prototype.constructor = Child;
Parent.prototype.theMethodName.call(inheritingChildInstance)
You can check this article on DEV.to; looks pretty accessible. I don't like the section using __proto__
(that is not supported everywhere, if coding for executing in browsers), but the rest is pretty good.
Upvotes: 1
Reputation: 29
A simple solution would be this:
function createMovie(title, duration, quote) {
return {
title: title,
duration: duration,
quote: quote,
isLongerThan(movie){
return movie.duration < this.duration
},
logQuote(){
console.log(this.quote)
}
}
}
var testMovie = createMovie("Star Wards", 121, "qoute1");
// testing the logQuote() method
testMovie.logQuote();
var otherMovie = createMovie("Spider Man", 125, "qoute2");
// testing the isLongerThan() method
console.log(testMovie.isLongerThan(otherMovie));
I understand that you should follow their instruction, on my assumption is for you to also learn different approaches from a different perspective (which I would say backward compatibility purposes). Your code is correct, it just happens they want a different solution but the same output.
Upvotes: 1