Doing some javascript prototypical inheritance, I would like to push the arguments in my Grades constructor and do the storage manipulation and push the data inside my this.students array using my storage method, and then use the values as I please within my other methods.
But the problem is that when I console log the constructor, it does what I need it to in terms of pushing the data in the this.students array but each object comes up as undefined.
This is weird because if I run the for loop inside the Grades constructor it will work perfectly. But I would like to have a separate method to do this, inside of within my Grades constructor
Any help in pointing me in the right direction would be great! Thanks!
function Grades(studentGrades) {
if(!Array.isArray(studentGrades)) return true;
this.students = [];
this.studentGrades = arguments.length;
this.numRows = 0;
this.numColumns = 0;
this.init();
}
/*
* Method to initialize functions
*/
Grades.prototype.init = function() {
this.storage();
};
/*
* Method to store a list of grades in an array object
*/
Grades.prototype.storage = function() {
for(var i=0; i < this.studentGrades; i++) {
this.students.push(this.studentGrades[i]);
}
};
/*
* Method to add grades
*/
Grades.prototype.addGrades = function(numRows, numColumns, initial) {
for(this.numRows; this.numRows < this.students.length; this.numRows++ ) {
}
};
/*
* Method to display the students average
*/
Grades.prototype.display = function() {
// body...
};
var inputGrades = new Grades( [89,78,93,78], [83,67,93,98], [93,99,73,88] );
console.log(inputGrades);
I think there are some problems with your code, especially with Grades constructor :
function Grades(studentGrades) {
if(!Array.isArray(studentGrades)) return true;
this.students = [];
this.studentGrades = arguments.length;
this.numRows = 0;
this.numColumns = 0;
this.init();
}
You are using an array as parameter to the function but you are passing thtree parameters (arrays), I think this line:
var inputGrades = new Grades( [89,78,93,78], [83,67,93,98], [93,99,73,88] );
Should be like this:
var inputGrades = new Grades( [[89,78,93,78], [83,67,93,98], [93,99,73,88] ]);
And the following line this.studentGrades = arguments.length; is useless in the constructor and may cause problems in your code, and should be replaced with :
this.studentGrades = arguments;
Or if you pass an array of arrays like I did you can use:
this.studentGrades = studentGrades;
Your problem is inside your storage function, originating from definition.
this.studentGrades is actually defined as the length of the array, not the array itself.
If you do not store the input array or pass it on through init(inputGrades) to storage(inputGrades), then you cannot access the original input from your storage prototype.
Better: change constructor bit to:
this.students = [];
this.studentGrades = studentGrades;
And your function inside storage to:
for(var i=0; i < this.studentGrades.length; i++) {
this.students.push(this.studentGrades[i]);
}
And you should be fine I think.
UPDATE: your original function call has a variable number of arguments.
Simplest way to get to complete answer is to change argument variable to:
var inputGrades = new Grades( [[89,78,93,78], [83,67,93,98], [93,99,73,88]]);
Now you send only one argument, an array of arrays.
Alternative: change the function to
function Grades() { // so no input argument
if(!Array.isArray(studentGrades)) return true;
this.students = [];
this.studentGrades = Array.prototype.slice.call(arguments);
this.numRows = 0;
this.numColumns = 0;
And then you should be able to send in multiple arguments.
Related
I've defined the methods "checkThreshold" and "checkOtherObject" in my prototype. checkOtherObject iterates across objects listed in attribute "nextDev" and is supposed to invoke checkThreshold for each object, thus:
// Protoype
function foo(otherObject) {
// attributes
this.nextDev=otherObject; // comma-delimited list of objects
// Method that references another method
this.checkOtherObject= function() {
successorList=this.nextDev.split(",");
for (var i=0; i<successorList.length;i++) {
successorList[i]['checkThreshold']();
}
}
// Method referenced by checkOtherObject
this.checkThreshold = function () {
<Do Stuff>
}
//Instantiations
var A = new foo ("B");
var B = new foo ("");
Thus, expected behavior is that A.checkOtherObject would invoke B.checkThreshold, but when I get to that line, B.checkThreshold isn't invoked. What am I doing wrong?
The root problem: you're trying to assign value of instances in theirselves. Note: what you're doing is still wrong, otherObject is a object, but it's a String object and it's not referring to the current foo's instance (this).
this.nextDev = otherObject
Other problem is that you're calling String().checkThreshold, but not foo().checkThreshold. You can check that at your statements:
successorList = this.nextDev.split(",");
for (var i = 0; i < successorList.length; i++) {
successorList[i]['checkThreshold']();
}
As you can see you're iterating string literals. String().split returns a object with string literals back, not a list with foo()'s.
/* confirm that the successorList is a array object */
successorList instanceof Array; // true
/* confirm that the first successorList's item is a string object */
typeof successorList[0] === "string"; // true
I'm basically not sure about what's your objective. It looks like you've a extra-ordinary giant confusion between String objects and objects. Maybe you want to store nextDev out of foo(), and at nextDev you want to store a Array object containing instances of foo? Then try:
var devs = [];
function foo(string) {
devs.push(this);
}
foo.prototype = {
checkOtherObjects: function() {
var me = this;
var myIndex;
var i = 0, len = devs.length;
for (; i < len; ++i) {
if (devs[i] === me) {
myIndex = i;
break;
}
}
for (i = myIndex + 1; i < len; ++i)
devs[i].checkThresold()
}
};
To offer a bit of a better explanation - yes, you CAN use window[successorList[i]], however, that is highly, highly not recommended, and here's why:
This becomes an issue if the variables no longer in the global scope. For example, if you place the code inside of a function, including an IIFE or a document ready function, you can no longer reference your variables from the window object, unless you were to declare them with window.A, window.B, but declaring global variables like that can get so messy, especially when working with other libraries/plugins.
So...how can you work around these issues? Simple - pass the object itself as #Bergi mentioned instead of passing the string that contains the name of the variable.
Here's what the code would look like:
// Protoype
function foo(otherObject) {
this.nextDev = otherObject || [];
// Method that references another method
this.checkOtherObject = function() {
this.nextDev.forEach(function(obj, index) {
obj.checkThreshold();
});
};
// Method referenced by checkOtherObject
this.checkThreshold = function() {
// Do Stuff
console.log("Checking Threshold for: ", this);
};
}
//Instantiations
var B = new foo(null);
var A = new foo([B]); //or [B, C, D, E, ...]
A.checkOtherObject();
I have a class from which i can create object:
function myClass () {
...
}
var obj = new myClass()
var obj2 = new myClass()
Each object represents one connection. It stores some important data ie connection id and so on. It works fine until i know number of connections, but in fact there may be 0 connections or 1000 connections. How can I easily put creating of objects into "for" loop to automatize process of making objects? Each object should be easily accessible so some convention of naming objects also is needed. I am surprised that i cant find such a solution in google. Any help would be apreciated.
I mean sth like this:
function myClass () {
...
}
for (i=0; i<sth.length; i++)
var obj$i = new myClass()
}
Kalreg.
Simple loop and push to an array:
var myStuff = [];
for (var i=0; i<sth.length; i++)
myStuff.push(new myClass());
}
console.log(myStuff[5]);
or an Object with named keys
var myStuff = {};
for (var i=0; i<sth.length; i++)
myStuff["foo"+i] = new myClass();
}
console.log(myStuff["foo5"]);
or an Array with map because I am waiting for a build...
var count = 15;
var myStuff = Array.apply(null, Array(count)).map(function () {return new myClass();});
function myClass(i)
{
this.id = i;
}
var n = 1000, objs = {};
for (var i=0;i<n;i++)
{
objs[i] = new myClass(i);
}
console.log(objs[25].id);
If you are familiar with OOP in Javascript and ... if you want to control the number of your instantiated objects and be able to access any object by its name, consider this approach:
function MyClass(){
...
MyClass.count++;
}
MyClass.count = 0; // static property (stores number of objects)
MyClass.objectStorage = {}; // object storage
MyClass.createObjects = function(number){ // static method (creates new objects)
var obj = null;
for (var i = 0; i < number; i++){
obj = new MyClass();
MyClass.objectStorage["object"+ MyClass.count] = obj;
}
};
MyClass.createObjects(10); // let's create 10 objects
MyClass.createObjects(5); // and some more
console.log(MyClass.count); // check how many objects were created
console.log(MyClass.objectStorage["object12"]); // accessing distinct object by name
I am trying to populate an object by using a JavaScript class. I am not even sure if I am doing it correctly, I am very new to JavaScript OOP.
var ImagesViewModel = {}; // Global object
function ImagesClass() {
this.addImage = function (iUrl) {
ImagesViewModel.push({ "ImageUrl": iUrl }) //< Error is here
}
}
var k = new ImagesClass()
k.addImage("http://www.yahoo.com")
k.addImage("http://www.xbox.com")
Basically I need an easy way to populate ImagesViewModel with multiple properties. Do I need to specify properties within ImagesViewModel? Maybe I can do all of this without having to specify a global variable?
I am getting the error
Object has no method PUSH
What you want is an array and not an object, push is a method on Array prototype and you are trying to use it on object.
Change:
var ImagesViewModel = {};
To:
var ImagesViewModel = [];
You can do it this way as well so that each instance of ImagesClass has its own set of images.
function ImagesClass() {
var _images = [];
this.addImage = function (iUrl) {
_images.push({ "ImageUrl": iUrl }) //< Error is here
}
this.getImages = function(){
return _images;
}
}
and use it as:
var k = new ImagesClass();
k.addImage("http://www.yahoo.com");
k.addImage("http://www.xbox.com");
var ImagesViewModel = k.getImages(); //You can either set it directly or as a property of object
console.log(ImagesViewModel);
Demo
the push method is only for Arrays, here you are trying to push() to an object, which is why it isn't working.
You will need to change var ImagesViewModel = {}; to var ImagesViewModel = [];
From a design perspective, you probably don't want your viewmodel to just be a flat array (even though you declared it as an object, as other posters pointed out).
I'd suggest declaring an array declaration to hold the images inside of your ImagesViewModel object.
var ImagesViewModel = { // ViewModel generic OBJECT
this.Images = new Array(); // prototype ARRAY object
};
function ImagesClass() {
this.addImage = function (iUrl) {
ImagesViewModel.Images.push({ "ImageUrl": iUrl })
}
}
Suppose I create a custom object/javascript "class" (airquotes) as follows:
// Constructor
function CustomObject(stringParam) {
var privateProperty = stringParam;
// Accessor
this.privilegedGetMethod = function() {
return privateProperty;
}
// Mutator
this.privilegedSetMethod = function(newStringParam) {
privateProperty = newStringParam;
}
}
Then I want to make a list of those custom objects where I can easily add or remove things from that list. I decide to use objects as a way to store the list of custom objects, so I can add custom objects to the list with
var customObjectInstance1 = new CustomObject('someString');
var customObjectInstance2 = new CustomObject('someOtherString');
var customObjectInstance3 = new CustomObject('yetAnotherString');
myListOfCustomObjects[customObjectInstance1] = true;
myListOfCustomObjects[customObjectInstance2] = true;
myListOfCustomObjects[customObjectInstance3] = true;
and remove custom objects from the list with
delete myListOfCustomObjects[customObjectInstance1];
but if i try to iterate through the list with
for (i in myListOfCustomObjects) {
alert(i.privilegedGetMethod());
}
I would get an error in the FireBug console that says "i.privilegedGetMethod() is not a function". Is there a way to fix this problem or an idiom in javascript to do what I want? Sorry if this is a dumb question, but I'm new to javascript and have scoured the internet for solutions to my problem with no avail. Any help would be appreciated!
P.S. I realize that my example is super simplified, and I can just make the privateProperty public using this.property or something, but then i would still get undefined in the alert, and I would like to keep it encapsulated.
i won't be the original object as you were expecting:
for (i in myListOfCustomObjects) {
alert(typeof i); // "string"
}
This is because all keys in JavaScript are Strings. Any attempt to use another type as a key will first be serialized by toString().
If the result of toString() isn't somehow unique for each instance, they will all be the same key:
function MyClass() { }
var obj = {};
var k1 = new MyClass();
var k2 = new MyClass();
obj[k1] = {};
obj[k2] = {};
// only 1 "[object Object]" key was created, not 2 object keys
for (var key in obj) {
alert(key);
}
To make them unique, define a custom toString:
function CustomObject(stringParam) {
/* snip */
this.toString = function () {
return 'CustomObject ' + stringParam;
};
}
var obj = {};
var k1 = new CustomObject('key1');
var k2 = new CustomObject('key2');
obj[k1] = {};
obj[k2] = {};
// "CustomObject key1" then "CustomObject key2"
for (var key in obj) {
alert(key);
}
[Edit]
With a custom toString, you can set the object as the serialized key and the value to keep them organized and still continue to access them:
var customObjectInstance1 = new CustomObject('someString');
var customObjectInstance2 = new CustomObject('someOtherString');
var customObjectInstance3 = new CustomObject('yetAnotherString');
myListOfCustomObjects[customObjectInstance1] = customObjectInstance1;
myListOfCustomObjects[customObjectInstance2] = customObjectInstance2;
myListOfCustomObjects[customObjectInstance3] = customObjectInstance3;
for (i in myListOfCustomObjects) {
alert(myListOfCustomObjects[i].privilegedGetMethod());
}
The for iteration variable is just the index, not the object itself. So use:
for (i in myListOfCustomObjects) {
alert(myListOfCustomObjects[i].privilegedGetMethod());
}
and, in my opinion, if you use an Object as an array index / hash, it just would be converted to the string "Object", which ends up in a list with a single entry, because all the keys are the same ("Object").
myListOfCustomObjects =[
new CustomObject('someString'),
new CustomObject('someOtherString'),
new CustomObject('yetAnotherString')
]
you will get access to any element by index of array.
Let's say I have some class called loopObject and I initialize every object through something like var apple = new loopObject(); Is there anyway to loop through all objects of a class so that some function can be performed with each object as a parameter? If there isn't a direct method, is there a way to place each new object into an array upon initialization?
You can make an array that contains every instance, like this:
function LoopObject() {
LoopObject.all.push(this);
}
LoopObject.all = [];
However, it will leak memory - your instances will never go out of scope.
function loopObject(){
this.name = 'test'
};
var list = [], x = new loopObject, y = new loopObject;
list.push(x)
list.push(y)
for ( var i = list.length; i--; ) {
alert( list[i].name )
}
var allObjects [] = new Array();
function loopObject() {
...
allObjects.push(this);
}
Then one can loop through all elements of allObjects as necessary using allObjects.length.