How do I add increment to two specific properties of a class? - javascript

Here are my instructions, I am having issues with getting two properties 'numberOfLikes' and 'comments' to use increment to adjust the amount of likes and comments. I don't know if I should use a for loop or if I just need the increment operator. I'm new to coding and apologize in advance.
/*
In the space below, add to the existing skeleton of a Tweet class.
A tweet should have a (dynamic) author, content, timeStamp, numberOfLikes, and comments.
A tweet should be able to increment the numberOfLikes and add to the list of comments.
Create several instances of your Tweet and log them to the console. Make sure the
tweet object instances behave as expected.
*/
class Tweet {
constructor(author, content, timeStamp, numberOfLikes, comments) {
this.author = author;
this.content = content;
this.timeStamp = timeStamp;
this.numberOfLikes = numberOfLikes;
this.comments = comments;
}
};
//This is code I was playing around with, doesn't work
this.add = function(numberOfLikes){
for(i = 0; i < numberOfLikes.length; i++){
console.log("You have " + numberOfLikes + " likes");
}
}
this.add = function(comments) {
for(i = 0; i < comments.length; i++) {
console.log("You have " + comments + " comments");
}
}
var tweet1 = new Tweet("Rihanna", "Fenty Beauty", "12:31 A.M.", 120193, 6782);
Thanks in advance!

A tweet should be able to increment the numberOfLikes
This should be a function to increase the numberOfLikes.
and add to the list of comments.
comments is probably an array. This means that you need a function to add a comment, to the list of your comments.
class Tweet {
constructor(author, content, timeStamp, numberOfLikes, comments) {
this.author = author;
this.content = content;
this.timeStamp = timeStamp;
this.numberOfLikes = numberOfLikes;
this.comments = comments;
}
increaseNumberOfLikes() {
this.numberOfLikes++
}
addComment(commentText) {
this.comments.push(commentText)
}
};
let tweet1 = new Tweet("The Weekend", "Some content", "15:31 P.M.", 9800, ["so cool", "do it again"])
tweet1.increaseNumberOfLikes()
tweet1.addComment("Great Song!")
console.log(tweet1)
You should create more tweets like above.

You can create functions that use += and array#push to increment numbers and add values to arrays.
Incrementing tweets:
incrementLikes(increment = 1) {
this.numberOfLikes += increment
}
Adding a comment to the array:
addComment(comment) {
this.comments.push(comment)
}
I also noticed that in your post you mentioned that this.comments was a list. So I made that change when initializing the class.
new Tweet("Rihanna", "Fenty Beauty", "12:31 A.M.", 120193, ["amazing", "wow"]);
Demo:
class Tweet {
constructor(author, content, timeStamp, numberOfLikes, comments) {
this.author = author;
this.content = content;
this.timeStamp = timeStamp;
this.numberOfLikes = numberOfLikes;
this.comments = comments;
}
incrementLikes(increment = 1) {
this.numberOfLikes += increment
}
addComment(comment) {
this.comments.push(comment)
}
};
var tweet1 = new Tweet("Rihanna", "Fenty Beauty", "12:31 A.M.", 120193, ["amazing", "wow"]);
tweet1.incrementLikes()
console.log(tweet1.numberOfLikes)
tweet1.incrementLikes()
console.log(tweet1.numberOfLikes)
tweet1.addComment("This is a comment")
console.log(tweet1.comments)

Within the class body you need to define prototypal functions like this:
class Tweet {
constructor(author, content, timeStamp, numberOfLikes, comments) {
this.author = author;
this.content = content;
this.timeStamp = timeStamp;
this.numberOfLikes = numberOfLikes;
this.comments = comments;
}
like() {
this.numberOfLikes++;
}
comment(comment) {
this.comments.push(comment);
}
}
const tweet1 = new Tweet("Rihanna", "Fenty Beauty", "12:31 A.M.", 120193, ["I hate I hate know-it-alls"]);
console.log(tweet1.numberOfLikes);
tweet1.like();
tweet1.like();
console.log(tweet1.numberOfLikes);
console.log(tweet1.comments);
tweet1.comment("I love you Rihanna!!")
console.log(tweet1.comments);
.as-console-wrapper { min-height: 100%!important; top: 0; }

This should work. You need to put the function definitions inside the class definition. I also modified the function names, because they conflict with each other.
class Tweet {
constructor(author, content, timeStamp, numberOfLikes, comments) {
this.author = author;
this.content = content;
this.timeStamp = timeStamp;
this.numberOfLikes = numberOfLikes;
this.comments = comments;
}
addLikes(numberOfLikes){
this.numberOfLikes += numberOfLikes
}
addComments(comments) {
this.comments += comments
}
};
// Initial tweet instance
var tweet1 = new Tweet("Rihanna", "Fenty Beauty", "12:31 A.M.", 120193, 6782);
// Call modifiers
tweet1.addLikes(5)
tweet1.addComments(7)
// Check the variables were modified
console.log(tweet1.numberOfLikes)
console.log(tweet1.comments)

Related

Object Constructors

I have a problem with creating a new Object in the constructor
My Aim is to take the user input and from that create a new object and push into an array using the constructor.
The problem is that when I try to fill the new input to create a new object it just replaced the old one with undefined values.
MY code :
let Book = document.querySelector("#one");
let Author = document.querySelector("#two");
let Year = document.querySelector("#three");
let Btn = document.querySelector("button");
Btn.addEventListener("click", () => {
Book = Book.value;
Author = Author.value;
Year = Year.value;
let myLibrary = [];
function newBook(name, author, year) {
this.name = name;
this.author = author;
this.year = year;
}
function addBookToLibrary(book, author, year) {
const Books = new newBook(book, author, year);
myLibrary.push(Books);
}
addBookToLibrary(Book, Author, Year);
console.log(myLibrary);
});
let Book = document.querySelector("#one");
let Author = document.querySelector("#two");
let Year = document.querySelector("#three");
let Btn = document.querySelector("button");
let myLibrary = [];
Btn.addEventListener("click", () => {
function newBook(name, author, year) {
this.name = name;
this.author = author;
this.year = year;
}
function addBookToLibrary(book, author, year) {
const Books = new newBook(book, author, year);
myLibrary.push(Books);
}
addBookToLibrary(Book.value, Author.value, Year.value);
console.log(myLibrary);
});
There are two mistakes in above code:
You are using local state of let myLibrary = []; which will be created on every click. It should be moved to a higher level so that on every click the value added can be preserved.
You are using same name of variables inside your function, which are overriding the Dom reference.

Class object overlapping

im still trying to learn and im trying to make a group of actors be added to a movie class, i made it work but i still have problems because if you add another actor the last one dissappears, i tried with a loop but i could do nothing.
class Movie {
constructor(title,year,duration){
this.title = title;
this.year = year;
this.duration = duration;
}
addCast(actors){
this.actors = actors
}
}
class Actor {
constructor(name,age)
{
this.name = name;
this.age = age;
}
}
const terminator = new Movie('Terminator I', 1985, 60);
const arnold = new Actor('Arnold Schwarzenegger', 50);
const otherCast = [
new Actor('Paul Winfield', 50),
new Actor('Michael Biehn', 50),
new Actor('Linda Hamilton', 50)
];
//From here it can not be modified
let movieOne = new Movie("Kong","2018","2h30m");
let movieTwo = new Movie("Joker","2019","2h03m");
let movieThree = new Movie("John Wick 3", "2019", "1h49m");
terminator.addCast(arnold);
terminator.addCast(otherCast);
//To here it can not be modified
console.log({movieOne,movieTwo,movieThree,terminator});
See? Arnold should be in the actors too but it isnt! Thanks for the help in advance.
Another thing, this is for an excercise and i can not modify the lines i commented.
You have
addCast(actors){
this.actors = actors
}
This does not add the passed actor array to the actors on the instance - it replaces the instance's actors with the passed argument. Calling addCast will result in whatever previously existed on actors being lost.
To help reduce bugs, it can help to name methods appropriately - for logic like this, I'd call it setCast, not addCast.
If you want to add onto the end of the existing cast, and you're not sure whether the argument will be a single actor to add or an array of actors to add, use:
addCast(actorOrActors) {
if (Array.isArray(actorOrActors)) {
this.actors.push(...actorOrActors);
} else {
this.actors.push(actorOrActors);
}
}
class Movie {
constructor(title, year, duration) {
this.title = title;
this.year = year;
this.duration = duration;
this.actors = [];
}
addCast(actorOrActors) {
if (Array.isArray(actorOrActors)) {
this.actors.push(...actorOrActors);
} else {
this.actors.push(actorOrActors);
}
}
}
class Actor {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const terminator = new Movie('Terminator I', 1985, 60);
const arnold = new Actor('Arnold Schwarzenegger', 50);
const otherCast = [
new Actor('Paul Winfield', 50),
new Actor('Michael Biehn', 50),
new Actor('Linda Hamilton', 50)
];
//From here it can not be modified
let movieOne = new Movie("Kong", "2018", "2h30m");
let movieTwo = new Movie("Joker", "2019", "2h03m");
let movieThree = new Movie("John Wick 3", "2019", "1h49m");
terminator.addCast(arnold);
terminator.addCast(otherCast);
//To here it can not be modified
console.log({
movieOne,
movieTwo,
movieThree,
terminator
});
This is because in your addCast() method, each time you call it, you are replacing the previous value instead of appending it
You overwrite arnold with your second addActors call.
Only add one actor at a time to an array of actors.
class Movie {
constructor(title,year,duration){
this.title = title;
this.year = year;
this.duration = duration;
this.actors = [];
}
addCast(actor){
this.actors.push(actor);
}
terminator.addCast(arnold);
terminator.addCast(otherCast[0]);
terminator.addCast(otherCast[1]);
terminator.addCast(otherCast[2]);

How can i access Closures preserved variables?

I'm trying to get the Closures preserved variables. I'm not sure if that even possible.
Here is my code:
function MyBooks (author, title){
this.author = author;
this.title = title;
return function addPrice(amount){
return amount;
}
}
var MyBooksObj=MyBooks('Tolkin','Hobbit');
alert(MyBooksObj('100 dollars')); //outpot: 100 dollars
alert("author: " + MyBooksObj.author); //outpot: author: undefined
alert("title: " + MyBooksObj.title); //outpot: title: undefined
Anybody knows how can i access 'author' and 'title' from outside the function using the variable 'MyBooksObj'?
Thanks!
Using the new operator on a function creates a new object with "this" bound to the result.
function MyBooks (author, title){
this.author = author;
this.title = title;
this.addPrice= function (amount){
return amount;
}
}
var MyBooksObj= new MyBooks('Tolkin','Hobbit');
alert(MyBooksObj.addPrice('100 dollars')); //output: 100 dollars
alert("author: " + MyBooksObj.author); //output: auther: Tolkin
alert("title: " + MyBooksObj.title); //output: title: Hobbit
Some error and wrong assumption were made in your code. This is what I feel is going on
No new syntax was used to define your new object.
When you return a function from an object the object loose hold of it internal structure and only return the function.
i.e MyBooks { author: 'Tolkin', title: 'Hobbit' }
becomes
[function: addPrice]
amount variable is not a closure, instead use this.amount which store it values in object memory.
so to correct your code. I will suggest this:`
function MyBooks(author, title){
this.author = author;
this.title = title;
this.amount = 0;
this.addPrice = function(amount){
return this.amount += amount;
}
}
var MyBooksObj= new MyBooks('Tolkin','Hobbit');
alert(MyBooksObj); //ouput object
alert(MyBooksObj.addPrice(100)); //output: 100 dollars
alert(MyBooksObj.addPrice(100)) //output: 200 dollars
alert("author: " + MyBooksObj.author); //output: auther: Tolkin
alert("title: " + MyBooksObj.title); //output: title: Hobbit`
You can also use Class and constructor :
class MyBooks {
constructor(author, title) {
this.author = author;
this.title = title;
}
setAmount(value) {
this.amount = value;
}
getAmount() {
return this.amount;
}
}
var MyBooksObj= new MyBooks('Tolkin','Hobbit');
MyBooksObj.setAmount('100 dollars');
alert(MyBooksObj.getAmount()); //outpout: 100 dollars
alert("author: " + MyBooksObj.author); //outpout: author: Tolkin
alert("title: " + MyBooksObj.title); //outpout: title: Hobbit
More details : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
Also interesting : https://coryrylan.com/blog/javascript-es6-class-syntax

Pure JS | Basket | closure

I am working on a small JavaScript application that will users to click on buttons on the page and pass it through to thier basket. The problem I have with doing this is I am unsure as to handle multiple buttons within the same function. I do not want to have to write out different functions for each button.
I am trying to do it OOP and have this so far:
var shop = {};
shop.items = [];
shop.Item = function(item, description, price) {
this.item = item;
this.description = description;
this.price = price;
};
shop.print = function() {
var itemCon = document.getElementById('items'),
html = "";
for(var i = 0; i < this.items.length; i++) {
html += '<div id="item">';
for(prop in this.items[i]) {
html += '<p><span class="title">' + prop + '</span>: ' + this.items[i][prop] + '</p>';
};
html += '<button id="' + this.items[i].item + '">Add to Basket</button>'
html += '</div>';
};
itemCon.innerHTML += html;
};
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
var basket = {};
basket.items = [];
basket.Item = function(item, description, price) {
this.item = item;
this.description = description;
this.price = price;
};
basket.add = function(data) {
this.items[items.length] = new Item(data.item, data.description, data.price);
};
basket.costCalculate = function() {
var cost = 0,
html = "Total: " + cost;
for(var i = 0; i < this.items.length; i++) {
cost += items[i].price;
};
return html;
};
basket.print = function() {
var output;
for(var i = 0; i < this.items.length; i++) {
for(prop in this.items[i]) {
console.log(prop + ": " + this.items[i][prop]);
};
};
};
function init() {
shop.print()
};
window.onload = init;
How would I determine what item has been clicked in order to run basket.add(data). How would I also pass through the data to that function for each item.
Also how would one go about implementing closure? I understand that it is inner functions having access to the variables of the outer functions, is what I am doing working with closure so far?
Okay, you've made a pretty good start but here are a couple suggestions:
It's probably a good idea to only have one instance of each Item. By that I mean it looks like you create a bunch of Items for to populate your shop's inventory, so for example:
var coat = new Item("Coat", "Warm", 20);
shop.items.push(coat);
Now when you click on your UI element, you ideally want this same instance of coat to go into your basket as well, so:
// User clicks on UI element, which triggers the following to execute:
basket.add( someItemIdentifier );
So now if you ever decide to increase all your prices by $10, you can simply do:
shop.increasePricesBy = function(amount) {
for(var i = 0; i < shop.items.length; i++) {
shop.items[i].price += amount;
}
// execute some function to update existing baskets' totals
};
I hope this makes sense for why there should be one instance of each item that multiple collections refer to.
This begs the question how you can tie the customer's interaction to adding the correct item. One solution could be to use arbitrary IDs to track items. For example:
// Create new item with some randomly generated ID
var coat = new Item({
id: "93523452-34523452",
name: "Coat",
description: "Warm",
price: 20
});
shop.items = {}; // Use a hash so it's easier to find items
shop.items[coat.id] = coat;
And your UI element could be some div like so:
<div class="add-product-button" data-id="93523452-34523452">
Add your click handler:
// Pure JS solution - untested
var clickTargets = document.getElementsByClassName("add-product-button");
for(var i = 0; i < clickTargets.length; i++) {
var clickTarget = clickTargets[i];
clickTarget.onClick = function() {
var itemID = clickTarget.getAttribute("data-id");
var item = shop.items[itemID];
basket.add(item);
};
}
// Equivalent jQuery code
$(".add-product-button").click(function() {
var id = $(this).attr('data-id');
var item = shop.items[id];
basket.add(item);
});
While your basket implements add something like:
basket.add = function(items) {
this.items.push(item);
};
And your costCalculate method gets a whole lot easier:
basket.costCalculate = function() {
var cost = 0;
for(var i = 0; i < this.items.length; i++) {
cost += this.item[i].price;
}
return cost;
};
Instead of doing this:
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
You can instead do:
shop.items.push(new shop.Item("Coat", "Warm", "20");
Probably a good idea to use a number instead of a string to represent the price.
In your shop.print loop, you probably don't want to hard code <div id="item"> because that will result in multiple divs with the same id.
Finally, I'm not going to try to answer your closure question here because I think that's been answered better than I can already so I'll just link you to some great resources that helped me understand it:
Best stackoverflow thread on how JS Closures work
MDN's doc on closures
Javascript: The Good Parts by Douglas Crockford. It's a tiny book, and talks about some great concepts - especially working with Prototypes which I suspect you'd find useful to help you with this project.
Let me know if you have any questions, I'm totally down to discuss them.

Javascript: Modify an object from a pointer

I'm making a digital library with three classes: Library, Shelf & Book. Shelves have their contents as an array of books. Books have two methods, enshelf and unshelf. When a book gets unshelfed it's supposed to set delete the instance of itself from the shelf it's on and then set it's location property to null. How can I modify the shelf it's sitting on? In the constructor if I change this.location, it will just give that property a new value instead of modifying the variable it points to. I feel like this is really simple and I'm overlooking something super basic.
var _ = require('lodash');
//books
var oldMan = new Book("Old Man and the Sea", "Ernest Hemingway", 0684801221);
var grapes = new Book("The Grapes of Wrath", "John Steinbeck", 0241952476);
var diamondAge = new Book("The Diamond Age", "Neal Stephenson", 0324249248);
//shelves
var shelf0 = new Shelf(0);
var shelf1 = new Shelf(1);
//libraries
var myLibrary = new Library([shelf0, shelf1], "123 Fake Street");
//these need to accept an unlimited amount of each
function Library(shelves, address) {
this.shelves = shelves; //shelves is an array
this.address = address;
this.getAllBooks = function() {
console.log("Here are all the books in the library: ");
for (var i = 0; i < this.shelves.length; i++) {
console.log("Shelf number " + i + ": ");
for (var j = 0; j < this.shelves[i].contents.length; j++) {
console.log(this.shelves[i].contents[j].name);
}
}
}
}
function Shelf(id) {
this.id = id;
this.contents = [];
}
function Book(name, author, isbn) {
this.name = name;
this.author = author;
this.isbn = isbn;
this.location = null;
this.enshelf = function(newLocation) {
this.location = newLocation;
newLocation.contents.push(this);
}
this.unshelf = function() {
_.without(this.location, this.name); //this doesn't work
this.location = null;
}
}
console.log("Welcome to Digital Library 0.1!");
oldMan.enshelf(shelf1);
myLibrary.getAllBooks();
oldMan.unshelf();
myLibrary.getAllBooks();
Small issue with your unshelf method, easily remedied:
this.unshelf = function() {
this.location.contents =
_.without(this.location.contents, this);
this.location = null;
}
Consider, however, that shelf and unshelf should be methods of Shelf, and not of Book. Also, if you must have this method, surround it with a guard, like so:
this.unshelf = function() {
if (this.location) {
this.location.contents =
_.without(this.location.contents, this);
this.location = null;
}
}
Couple of small issues:
without works on arrays and returns a copy of the array with the elements removed - the original is untouched. So you need to pass location.contents instead of just location and reassign it back to location.contents.
Also you add the whole book to the Shelf, then try to remove it by name, so it doesn't match and get removed. So just pass this to without:
this.unshelf = function() {
if (this.location) {
this.location.contents = _.without(this.location.contents, this);
this.location = null;
}
}

Categories