Retrieving a value held in all instances of an object - javascript

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

Related

is the following way also correct for constructor functions in javascript?

let construct = function(name = "john", last = "marks") {
return {
name: name,
last: last,
};
};
let me = new construct("mike", "tyson");
console.log(me);
You do not have a constructor function.
A constructor function is one you can call with the keyword new in order to produce a new instance of said function. However, yours that just produces plain objects with no inheritance:
Your implementation:
let construct = function(name = "john", last = "marks") {
return {
name: name,
last: last,
};
};
let me = new construct("mike", "tyson");
console.log(me instanceof construct); //false
Proper constructor function:
let construct = function(name = "john", last = "marks") {
this.name = name;
this.last = last;
};
let me = new construct("mike", "tyson");
console.log(me instanceof construct); //true
This matters if you want to use prototypal inheritance for the produced instances:
let construct = function(name = "john", last = "marks") {
this.name = name;
this.last = last;
};
let me = new construct("mike", "tyson");
construct.prototype.fullName = function() {
return `${this.name} ${this.last}`;
}
console.log(me.fullName()); //"mike tyson"
In order to produce proper instances with new, it needs to either return nothing (which implicitly produces undefined) or return anything other than an object:
function example() {
this.foo = "bar";
return "this is not an object";
}
console.log(example());
console.log(new example());

Unused JavaScript arguments

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: '' }

Using an array inside a constructor using Javascript

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());

How to create a method in object literal notation?

I learned there are 2 types of creating objects. First: object literal notation and second: Object constructor. I have learned that there are also methods and functions, but I couldn't understand how to create a method in object literal notation? In object constructor I just write:
var bob = new Object();
bob.age = 30;
bob.setAge = function(newAge) {
bob.age = newAge;
};
Can you please tell me how to do the same when writing object literal notation.
var bob = {
age: 30
};
Syntactically, the change is very simple :
var bob = {
age: 30,
setAge: function (newAge) {
bob.age = newAge;
}
};
But as you can see, there's a problem : as in your code it uses the external bob variable so this wouldn't work if you change the value of the bob variable.
You can fix that with
var bob = {
age: 30,
setAge: function (newAge) {
this.age = newAge;
}
};
Note that at this point you should check whether what you need isn't, in fact, a class, which would bring some performance improvements if you have several instances.
Update: ECMAScript 6 now allows methods to be defined the same way regardless of whether they are in an object literal:
var bob = {
age: 30,
setAge (newAge) {
this.age = newAge;
}
};
Its nothing different and as easy as
var bob = {
age: 30,
setAge: function( newAge ) {
this.age = newAge;
}
};
Alternatively, you can create a real setter function either by invoking Object.defineProperty() or as simple as
var bob = {
age: 30,
firstName: 'j',
lastName: 'Andy',
set setName( newName ) {
var spl = newName.split( /\s+/ );
this.firstName = spl[ 0 ];
this.lastName = spl[ 1 ];
}
}
Where you could go like
bob.setName = "Thomas Cook"; // which sets firstName to "Thomas" and lastName to "Cook"
The last code you posted is missing a comma. Also, you don't need a ';' after a function definition of an object's property. Like this:
var object2 = {
name: "Fred",
age: 28,
club: "Fluminense",
bio2: function (){
console.log(this.name +" is "+ this.age + " years old and he is playing in "+ this.club);
}
};
This is the way to solve this exercise using literal object creation method:
var setAge = function (newAge) {
this.age = newAge;
};
var bob = new Object();
bob.age = 30;
bob.setAge = setAge;
var susan = {
age: 25,
setAge: setAge
}
susan.setAge(35);
If you want encapsulation, you might use the following syntax(self-executing function). Here age is not accessible from the outside of the object bob.
var bob = (function() {
//...private
var age = 30;
function setAge(newAge) {
age = newAge;
};
function getAge() {
return age;
}
// Public api
return {
setAge: setAge,
getAge: getAge
}
}());
bob.setAge(50);
alert(bob.getAge());
jsfiddle: http://jsfiddle.net/61o9k98h/1/
Starting with ECMAScript 2015, a shorter syntax for method definitions on objects initializers is introduced. It is a shorthand for a function assigned to the method's name
const bob = {
age: 30,
setAge(age) {
this.age = age;
},
};
alert(bob.age); // 30
bob.setAge(63); // set age = 63
alert(bob.age); // 63
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions
Like this:
var bob = {
age: 30,
setAge: function (age) {
this.age = age;
}
}
alert(bob.age); // 30
bob.setAge(45); // set age = 45
alert(bob.age); // 45

javascript inheritance and instance variables

I'm trying to understand how inheritance works in JS. Suppose we have a class:
Class = function () {
this.A = 'A';
this.B = 'B';
};
and we are trying to extend it
SubClass = function () {};
SubClass.prototype = new Class();
Do I understance correctly that after inheritance properties A and B are common for all instances of SubClass, since they belong to it's prototype? If yes, how can Class be extended so that A and B do not be part of prototype?
UPD: note that Class uses A and B, so I can't declare them in SubClass.
Thank you in advance!
All I want is to make A and B be accessible and specific for each
"instance"
The typical way of doing this is to pass parameters and assign them to properties. Then you can use call to reference the super class. In other words:
function Person( name, age ) {
this.name = name;
this.age = age;
}
function Student( name, age, grade ) {
Person.call( this, name, age ); // call super-class with sub-class properties
this.grade = grade;
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
var roger = new Student( 'Roger', 18, 'A+' );
You can use properties in parent class without defining:
Class = function () {
this.sum = function() {
return this.a+this.b;
}
};
SubClass = function () {
this.a = 5;
this.b = 6;
};
SubClass.prototype = new Class();
var z = new SubClass();
z.sum(); //11
Another way: Create function in prototype which creates your properties:
Class = function () {
this.makeAB = function() { //called with context of SubClass
this.A = 'A';
this.B = 'B';
}
};
SubClass = function () { this.makeAB() };
SubClass.prototype = new Class();
var z = new SubClass();
z.A = 'AAA';
z.B = 'BBB';
var z2 = new SubClass();
console.log(z)
console.log(z2)

Categories