I've been trying to find a way to correctly define an array as one of the constructor values. Let's say we have a student and we need to have an array with his grades and then using the array we need to get an average from the student's grades. Sadly, I only found some threads addressing this in other programming languages. This is what I thought would work:
function student(name, surname, number, grades) {
this.name = name;
this.surname = surname;
this.number = number;
this.grades = [];
this.average = function(grades) {
var sum = 0;
for(var i = 0; i < grades.length; i++) {
sum + = grades[i];}
var average = sum / grades.length;
return average;
}
}
And then
var student1 = new student("Peter","Cat",14444,[2,3,4]);
console.log(student1);
Unfortunately, it shows my grades array as blank and I can't see if my average function is working properly. Which part(s) should I change so that I would actually have some values in the grades array?
Thank you.
You have a couple things messed up. If you are going to pass the grades array in as an argument, then you need to set grades with this:
this.grades = grades;
Also in the average function you need to refer to grades with this.grades not just grades. This will allow you to add more grades later and still get the correct average. You could also consider making the grades optional by defining the constructor with something like:
function student(name, surname, number, grades =[])
Then if you don't pass in a value, an empty array will be waiting for you.
In the end you might have something like:
function student(name, surname, number, grades = []) {
this.name = name;
this.surname = surname;
this.number = number;
this.grades = grades;
this.average = function() {
return this.grades.reduce((a, c) => a + c, 0) / this.grades.length
}
}
var student1 = new student("Peter", "Cat", 14444, [2, 3, 4]);
console.log("Average: ", student1.average())
// add another grade:
student1.grades.push(6)
console.log("New Average: ", student1.average() )
You can solve same problem by using ES6, in your code, you are initializing this.grade=[] with an empty array inside function so further processing of average will be done on empty array only. For good practice, function parameters should be assigned with a default value, so that if mistakenly we do not pass an array as an argument then the function parameter will use the default value. Attaching code snippet for easy understanding in ES6.
class std{
constructor(name, surname, number, grades = []) {
this.name = name;
this.surname = surname;
this.number = number;
this.grades = grades;
}
average() {
if(this.grades.length !== 0){
return this.grades.reduce((previous, current) => previous + current, 0) /
this.grades.length
} else { return "no grades mentioned"; }
}
}
var student1 = new std("Peter", "Cat", 14444, [1, 3, 4]);
console.log("Average: ", student1.average());
//add new student
var student2 = new std("Prasanna", "sasne", 14444);
console.log(student2);
//student2.grades.push(7)
//console.log("New Average: ", student2.average() )
You're already passing grades into the student() function, so you don't need to pass it in to the student.average function (as the inner function will already have access to the outer function parameter). Because of this, you also don't need to set this.grades = [].
Also, sum + = grades[i] should be sum += grades[i].
Simply fixing this error, then omitting passing grades into the inner function will correctly show the average, as can be seen in the following:
function student(name, surname, number, grades) {
this.name = name;
this.surname = surname;
this.number = number;
this.average = function() {
var sum = 0;
for (var i = 0; i < grades.length; i++) {
sum += grades[i];
}
var average = sum / grades.length;
return average;
}
}
var student1 = new student("Peter", "Cat", 14444, [2, 3, 4]);
console.log(student1.average());
Your initialization of the variable is an empty array.
this.grades = [];
Should be
this.grades = grades;
However, I recommend that you study some javascript ES6 / ECMAScript 2015 and use classes.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
class Student {
constructor(grades) {
//... Other code
this.grades = grades;
}
}
you can use this line :
function student(name, surname, number, grades){ }
instead of this:
function student(name, surname, number, grades = [ ]){ }
function student(name, surname, number, grades) {
this.name = name;
this.surname = surname;
this.number = number;
this.grades = grades;
this.average = function() {
return this.grades.reduce((a, c) => a + c, 0) / this.grades.length
}
}
var student1 = new student("Peter", "Cat", 14444, [2, 3, 4]);
console.log("Average: ", student1.average())
// add another grade:
student1.grades.push(6)
console.log("New Average: ", student1.average() )
We can use the Object Method to store the Average value:
function Student(name, surname, number, grades = [])
{
this.name = name;
this.surname = surname;
this.number = number;
this.grades = grades;
//Method to calculate the Average
this.average = function()
{
if(this.grades.length !==0)
{
//Return the Average Calculation
return this.grades.reduce((previous, current) => previous + current, 0) / this.grades.length
}
else
{
//This will return if grades not provided
return "No Grades Mentioned"
}
}
}
//With Grades
var student1 = new Student("Srinivasan", "Raja", 1635, [22,43,67,89,90]);
console.log(student1, "Average: "+ student1.average());
//Without Grades
var student1 = new Student("Denny", "Lawrence", 1635);
console.log(student1, "Average: "+ student1.average());
Related
I am new to JavaScript. And I want to make sense of a feature in JavaScript. Please consider the following example:
function Dog(name) {
this.name = name
}
Dog.prototype.bark = function() {
console.log(this.name +" :Hello, human.");
}
var max = new Dog("Max", "Buddy")
max.bark();
As you can see two arguments were passed into making a new dog object while only one (name) was required.
I know that the second argument is unused, but where is it stored/ is there any utility to passing an extra argument?
Thank you in advance!
They can be retrieved in the arguments object:
arguments is an Array-like object accessible inside functions that
contains the values of the arguments passed to that function.
function Dog(name) {
console.log(arguments);
this.name = name;
}
Dog.prototype.bark = function() {
console.log(this.name +" :Hello, human.");
}
var max = new Dog("Max", "Buddy");
max.bark();
The modern alternative would be the spread operator:
function Dog(...names) {
console.log(names);
}
var max = new Dog("Max", "Buddy");
They are store in arguments array :
function Dog(name) {
this.name = name
console.log(arguments)
}
Dog.prototype.bark = function() {
console.log(this.name +" :Hello, human.");
}
var max = new Dog("Max", "Buddy", "Arm", {name: "Jacob"})
max.bark();
if you are not using js in strict mode you can access the arguments property of function.
function Dog(name) {
this.name = name
// all the arguments are inside arguments property of function
console.log(arguments);
}
Dog.prototype.bark = function() {
console.log(this.name +" :Hello, human.");
}
var max = new Dog("Max", "Buddy")
max.bark();
Javascript is a dynamic language. Same function can accept dynamic arguments. There are multiple way to access all variable passed 2 a function/constructor.
Using arguments.
Using vaargs or rest operator.
Mix of rest operator and arguments.
It depends how you want to use the values. See the below examples.
function DogArgs(name) {
this.name = name;
console.log(arguments); // array like structure [Arguments] { '0': 'Max', '1': 'Buddy' }
}
function DogRest(...names) {
this.name = names[0];
console.log(names); // Array [ 'Max', 'Buddy' ]
}
function DogPartialRest(name, ...others) {
this.name = name;
console.log(others); // Array [ 'Buddy' ]
}
var max1 = new DogArgs("Max", "Buddy");
var max2 = new DogRest("Max", "Buddy");
var max3 = new DogPartialRest("Max", "Buddy");
Example 1: Using arguments
function sum() {
const values = Array.from(arguments); // convertin array, since arguments is not array
return values.reduce((sum, val) => (sum += val), 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4)); // 10
Example 2: Using vaargs or rest operator.
function sum(...values) {
return values.reduce((sum, val) => (sum += val), 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4)); // 10
Example 3: Mix of rest operator and arguments
function Person(name, age, ...rest) {
this.name = name
this.age = age
this.salary = 0
if(rest.length) {
this.salary = rest[0]
this.address = rest[1] || ''
}
}
console.log(new Person("deepak", 30)) // Person { name: 'deepak', age: 30, salary: 0 }
console.log(new Person("deepak", 30, 2000)) // Person { name: 'deepak', age: 30, salary: 2000, address: '' }
How can I access a certain argument in a Object constructor which is an Array and pick a index in the array to do a calculation with (get the total of all the items for that costumer).
I have been trying to get the price value in the Items Object and add the total for each costumer object in the order Array.
I am selecting them from a selection element in HTML, which is populated in JS.
console.log(costomer[0].order[1]);
I have tried various syntax but when I choose the index of the costumer array I get undefined as the result.
//Waiter Constructor
function Costumer(name, order, total) {
this.name = name;
this.order = [];
this.total = total;
}
//CostomerArray
const costumers = [
new Costumer('Timo'),
new Costumer('Bill')
];
//This is done twice in the same way for the items as well both populate the
//selection element.
custumer.forEach(({ name }) => costumerEl.options.add(new Option(name)));
//Item constuctor
function Item(item, price) {
this.item = item;
this.price = price;
}
//Main food array
const items = [
new Item('Keyboard', 14.50),
new Item('mouse', 10)
];
//This is the function which adds the items to the array when the form is submitted.
const formEl = document.getElementById('mainForm');
formEl.onsubmit = function(e) {
const foodItem = foodMain.options[foodMain.selectedIndex].value;
const costumerName = costumerEl.options[costumerEl.selectedIndex].value;
const costumer = costumer.find(({ name }) => name === costumerName);
if (costomer && itemItem) {
waiter.order.push(itemItem);
console.log(costumers);
};
return false; // prevents redirect/refresh
};
The expected result would be for 'Timo' to order a mouse and keyboard and to add both price arguments in the order array to give a total.
ex.
(2) [Waiter, Waiter]
0: Waiter
name: "Timo"
order: Array(2)
0: "Keyboard (14.5)"
1: "Mouse (10)"
length: 2
__proto__: Array(0)
total: undefined
__proto__: Object
I want to calculate the total of the items that 'Timo' has ordered.
Your question has a lot of problems but i can help you with some of them.
First, you should change Costumer and Item to classes.
//Waiter Constructor
function Costumer(name, order, total){
this.name = name;
this.order = [];
this.total = total;
}
to
//Waiter Constructor
class Costumer {
constructor(name, order, total){
this.name = name;
this.order = [];
this.total = total;
}
}
the same goes to Item
//Item constuctor
class Item {
constructor(item, price) {
this.item = item;
this.price = price;
}
}
and then you can calculate the total price of 'Timo' items like this:
(assuming that 'Timo' will be the first on the customers Array)
var totalPrice = 0;
for(let i = 0; i < costumer[0].order.length; ++i) {
totalPrice += costumer[0].order[i].price;
}
I am working on a Person constructor function that takes a name and age as its parameters, and trying to implement a method that retrieves all the 'Person' instances current age value and outputs the average. Here's my code...
var Person = (function() {
//private state
var inst = 1;
function Person(name, age) {
this.name = name;
this.age = age;
Object.defineProperty(this, "age", {
get: function() {
return age;
},
set: function(num) {
age = num;
}
});
Object.defineProperty(this, "_id", {
value: inst++
});
}
//Attempt to return number of instances divided by all current Person weights
Person.prototype.aveAge = function() {
return inst;
};
return Person;
}());
var jim = new Person("jim", 32);
var richard = new Person("richard", 27);
richard.age = 28;
var alfie = new Person("alfie", 42);
Person.aveAge() //Returns TypeError: Person.aveAge is not a function
I have set up a variable that is shared across all instances (inst) that increments each time an another instance is created and assigns a unique id. I cannot figure out how I can get to each 'age' value of all Person instances in existence using the aveAge prototype I have added at the bottom. I am also getting a 'TypeError: Person.aveAge is not a function' when I attempt to call it to even test that variable 'inst' holds the correct number of instances. Does anybody know where I am going wrong?
It feels strange to keep ages on a person when it references people. Notice that hanging things on __proto__ makes them available from the constructor (Person), while hanging things on prototype makes them available from the instance (richard). If Age is updated, it needs to be done via setAge so the PeopleTracker knows to update it's memory. Also, in my example, the average is only calculated when needed rather than each time a person wants to know what is is.
var peopleTracker = {
_count: 0,
_ages: [],
averageAge: 0,
addPerson: function (age) {
var pt = peopleTracker;
pt._count += 1;
pt._ages.push(age);
pt.getAverage();
},
getAverage: function () {
var sum = 0,
pt = peopleTracker;
sum = pt._ages.reduce(function (a, b) {
return a + b;
});
pt.averageAge = Math.round(sum / pt._count);
},
update: function (oldAge, newAge) {
var pt = peopleTracker,
ages = pt._ages,
i = ages.indexOf(oldAge);
ages.splice(i, 1, newAge);
pt.getAverage();
}
};
var Person = function (name, age) {
this.name = name;
this.age = age;
peopleTracker.addPerson(age);
};
Person.__proto__ = { // available from the constructor
Constructor: Person,
setAge: function (age) {
var oldAge = this.age;
this.age = age;
peopleTracker.update(oldAge, age);
},
aveAge: function () {
return peopleTracker.averageAge;
}
};
Person.prototype = Person.__proto__; // now also available from the instance
var jim = new Person("Jim", 32),
richard = new Person("Richard", 27),
alfie = new Person("Alfie", 42);
Person.aveAge(); // 34
richard.aveAge(); // 34
richard.setAge(20);
Person.aveAge(); // 31
richard.aveAge(); // 31
I'm trying to learn JavaScript and am going through an exercise where I'm creating a grocery list that populates with a food, quantity, and cost. I cannot seem to pass in multiple variables or make an array of arrays. I tried some other options like "new Object" but I can't get anything off the ground. Give me a clue?
var groceryList = function(food, quantity, price) {
var theItem = [food, quantity, price]
var theList = new Array();
theList.push(theItem)
}
myList = new groceryList("cookie", 2, 1.00)
console.log(myList)
Use this
var groceryList = function(food, quantity, price) {
var theItem = [food, quantity, price]
var theList = new Array();
theList.push(theItem);
return theList;
}
myList = new groceryList("cookie", 2, 1.00)
console.log(myList)
If you want to use objects, then you need to change your thinking a little bit. When you create an object with new then the constructor gets called.
function GroceryList(food, quantity, price) {
this.food = food;
this.quantity = quantity;
this.price = price;
}
GroceryList.prototype.toString = function() {
return this.food + (this.quantity).toString() + (this.price).toString();
}
// lazy array syntax
var GroceryListPool = [];
// popular the array list pool
var list1 = new GroceryList("Butter", 2, 3.999);
GroceryListPool.push(list1);
To iterate the GroceryListPool array:
for(var i = 0; i < GroceryListPool.length; i++) {
var list = GroceryListPool[i];
// list is an object of type GroceryList
// technically it is not a "type", but you know what I mean.
alert(list);
}
That's not even really a Constructor, yet. Check this out.
function groceryList(food, quantity, price){
this.items = {};
if(food !== undefined){
this.items[food] = {quantity:quantity, price:price, total:quantity*price};
}
this.addItem = function(food, quantity, price){
this.items[food] = {quantity:quantity, price:price, total:quantity*price};
}
this.getFood(food){
return this.items[food];
}
this.getQuantity = function(food){
return this.items[food].quantity;
}
this.getTotal = function(food){
return this.items[food].total;
}
this.getItemsByPrice(low, high){
var r = {}, t = this.items;
for(var i in t){
var f = t[i], p = f.price;
if(p >= low && p <= high){
r[i] = f;
}
}
return r;
}
}
var groc = new groceryList('potato', 4, 0.89);
groc.addItem('orange', 10, 1);
console.log(groc.getQuantity('potato'));
console.log(groc.getTotal('orange'));
console.log(groc.getFood('orange').price);
// same as
console.log(groc.getPrice('orange'));
// or
console.log(groc.items.orange.price);
groc.addItem('pear', 200, 0.75);
console.log(groc.getItemsByPrice(0.25, 0.99)); // should be Object with 'potato' and 'pear'
I have the following array of objects which orders the list. The problem is that the ordering is wrong because the OrderId property is not unique across all headings. The OrderId starts from 1 for each heading, hence the problem.
Please help!
Many thanks
// Class
var Item = function(orderId, forename, surname, heading) {
this.OrderId = orderId;
this.Forename = forename;
this.Surname = surname;
this.Heading = heading;
};
// Creation of objects
var obj1 = new Item(1, "James", "Smith", "Heading1");
var obj2 = new Item(2, "Tracey", "Janes", "heading1");
var obj3 = new Item(3, "Sarah", "Cann", "Heading1");
var obj4 = new Item(1, "Matt", "Bars", "Heading2");
var obj4 = new Item(2, "Alex", "Magi", "Heading2");
// Add to array
tempArray.push(obj1);
tempArray.push(obj2);
tempArray.push(obj3);
tempArray.push(obj4);
// Sort array
tempArray.sort(function(a, b) {
var a1 = a.OrderId, b1 = b.OrderId;
if (a1 == b1) return 0;
return a1 > b1 ? 1 : -1;
});
// Render array to screen - order by OrderId
for(var i = 0; i < tempArray.length; i++) {
console.log(tempArray[i].Heading);
console.log(tempArray[i].Forename + " " + tempArray[i].Surname);
}
The output I need:
Heading 1
James Smith
Tracey Janes
Sarah Cann
Heading 2
Matt Bars
Alex Magi
Because the OrderId is not unique across I get the following issue
Heading 1
James Smith
Matt Bars
Alex Magi
Tracey Janes
Sarah Cann
Heading 2
If you want to default order by id then you can add toString method to your Object and return the id as string as this is used by .sort:
var Item = function(orderId, forename, surname, heading) {
this.OrderId = orderId;
this.Forename = forename;
this.Surname = surname;
this.Heading = heading;
};
Item.prototype.toString=function(){
return this.OrderId+"";
};
// create a bunch of Items
tmpArray.sort();// done, it's sorted by id now
If you want to sort it on certain key(s) then you can pass a sort function to tmpArray.sort
function sortItems(arr,keys){
var len=keys.length;
arr.sort(function(a,b){
var i=0;
while(a[keys[i]]===b[keys[i]]&&i<len){
i++;
}
return i===len?0:(a[keys[i]]>b[keys[i]])?1:-1;
}
};
// sort by Surname then by Forename (if 2 items have same Surname)
sortItems(tmpArray,["Surname", "Forename"]);
Looking at your question again I see it's not the sorting that is the problem but the grouping. here is a function that would implement grouping for you.
var Item = function(orderId, forename, surname, heading) {
this.OrderId = orderId;
this.Forename = forename;
this.Surname = surname;
this.Heading = heading;
};
// Creation of objects
var obj1 = new Item(1, "James", "Smith", "Heading1");
var obj2 = new Item(2, "Tracey", "Janes", "Heading1");
var obj3 = new Item(3, "Sarah", "Cann", "Heading1");
var obj4 = new Item(1, "Matt", "Bars", "Heading2");
var obj5 = new Item(2, "Alex", "Magi", "Heading2");
var tempArray=[];
tempArray.push(obj1);
tempArray.push(obj2);
tempArray.push(obj3);
tempArray.push(obj4);
tempArray.push(obj5);
function sortItems(arr,keys){
var len=keys.length;
arr.sort(function(a,b){
var i=0;
while(a[keys[i]]===b[keys[i]]&&i<len){
i++;
}
return i===len?0:(a[keys[i]]>b[keys[i]])?1:-1;
});
};
// sort on Heading
sortItems(tempArray,["Heading","Forename","Surname"]);
function groupBy(arr,key){
var i=0,ret={};
for(i=0;i<arr.length;i++){
if(!ret[arr[i][key]]){
ret[arr[i][key]]=[];
}
ret[arr[i][key]].push(arr[i]);
}
return ret;
};
var grouped=groupBy(tempArray,"Heading");
var key="",i =0,ret=[];
// If any code in your page adds to Object.prototype then this breaks
// like Object.prototype.mySmartFuncion since mySmartFunciton will show
// up as key in for key in anyObject
for(key in grouped){
ret.push(grouped[key][0].Heading);
for(i=0;i<grouped[key].length;i++){
ret.push("\t"+grouped[key][i].Forename + grouped[key][i].Surname);
}
}
console.log(ret.join("\n"));