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
Related
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.
function Person() {
var self = this;
self.personName="";
self.animals=[];
}
function Animal(){
var self=this;
self.animalName="";
self.run=function(meters){
.....
}
}
Server response:
[{personName:John,animals:[{animalName:cheetah},{animalName:giraffe}]} , {personName:Smith,animals:[{animalName:cat},{animalName:dog}]} ]
I'm getting Person array from server. I want to cast generic Person array to typed Person array. So I can use
persons[0].Animals[2].Run();
I founded Javascript's
Object.create(Person,person1);
But I want cross-browser version of it with array support
ObjectArray.create(Person,persons);
or
Object.create(Person[],persons);
Creating an object in JavaScript requires the invocation of its constructor. So, at first you will need to find the correct arguments, which may not always be just properties. After that, you can reassign all public properties from the JSON-parsed object to the created instances.
A general solution would be that every constructor accepts any objects that look like instances (including real instances) and clones them. All the internal logic needed to create proper instances will be located in the right place then.
Or even better than overloading the constructor might be to create a static method on your class that takes objects and creates instances from them:
Person.fromJSON = function(obj) {
// custom code, as appropriate for Person instances
// might invoke `new Person`
return …;
};
Your case is very simple, as you don't have any arguments and only public properties. To change {personName:John,animals:[]} to an object instance, use this:
var personLiteral = ... // JSON.parse("...");
var personInstance = new Person();
for (var prop in personLiteral)
personInstance[prop] = personLiteral[prop];
You can also use Object.assign functionality (or e.g. jQuery.extend pre-ES6) for this:
var personInstance = Object.assign(new Person(), personLiteral);
The creation of the Animal instances works analogous.
As JSON does not transport any information about the classes, you must know the structure before. In your case it will be:
var persons = JSON.parse(serverResponse);
for (var i=0; i<persons.length; i++) {
persons[i] = $.extend(new Person, persons[i]);
for (var j=0; j<persons[i].animals; j++) {
persons[i].animals[j] = $.extend(new Animal, persons[i].animals[j]);
}
}
Btw, your run methods seems likely to be added on the Animal.prototype object instead of each instance.
It seems like you have classes that have some prototype methods and you'd just like to be able to make your objects use those methods. http://jsfiddle.net/6CrQL/3/
function Person() {}
Person.prototype.speak = function() {
console.log("I am " + this.personName);
};
Person.prototype.runAnimals = function() {
this.animals.each(function(animal){
animal.run();
})
};
function Animal() {}
Animal.prototype.run = function() {
console.log("My Animal " + this.animalName+ " is running");
}
var untypedPersons = [{personName:"John",animals:[{animalName:"cheetah"},{animalName:"giraffe"}]} , {personName:"Smith",animals:[{animalName:"cat"},{animalName:"dog"}]} ];
function fromArray(arr, constructor) {
return arr.map(function(obj){
var typed = Object.create(constructor.prototype);
// Now copy properties from the given object
for (var prop in obj) {
typed[prop] = obj[prop];
}
return typed;
});
}
var persons = fromArray(untypedPersons, Person);
// Attach prototype to each animals list in person
persons.each(function(person){
person.animals = fromArray(person.animals, Animal);
});
persons.each(function(person){
person.speak();
person.runAnimals();
});
This could all be a lot easier (and we could avoid all the copying) if everybody supported the __proto__ property http://jsfiddle.net/6CrQL/2/
persons.each(function(person){
person.__proto__ = Person.prototype;
person.animals.each(function(animal){
animal.__proto__ = Animal.prototype;
});
});
persons.each(function(person){
person.speak();
person.runAnimals();
});
First of all: In JavaScript you don't have classes like in C++, Java or C#. So you cannot really have a typed array.
What you are doing should basically work for variables, but not for functions. So you would have to add the functions first. Have a look at the following code to get an idea.
<script type="text/javascript">
function Person() {
var self = this;
self.personName="";
self.animals=[];
}
function Animal(){
var self=this;
self.animalName="";
self.run=function(meters){
7/... do something
}
}
var persons = [{personName:"John",animals:[{animalName:"cheetah"},{animalName:"giraffe"}]} , {personName:"Smith",animals:[{animalName:"cat"},{animalName:"dog"}]} ];
//use this to assign run-function
var a = new Animal();
//assign run-function to received data
persons[0].animals[0].run = a.run;
//now this works
persons[0].animals[0].run();
</script>
How about creating a Static method on Person Class, which will accept your server response and create required variables.
This is just an idea. Please see if this fits in your problem.
//Static method
Person.createObjects = function( response ) {
var persons = [];
for ( var p = 0; p < response.length; p++ ) {
//Create Person
var person = new Person( response[p].personName );
//Create Animals
for ( var a = 0; a < response[p].animals.length; a++ ) {
var animal = new Animal( response[p].animals[a].animalName );
//Push this animal into Person
person.animals.push ( animal );
}
//Push this person in persons
persons.push ( person );
}
//Return persons
return persons;
}
//Now Create required persons by passing the server response
var persons = Person.createObjects ( response );
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.
I've been learning more about javascript's prototypal inheritance. I know there is a somewhat fierce debate on whether to extend native objects and I'd like to side step that whole debate entirely in this question.
Is it possible to extend only descendent object in javascript?
To extend all objects I can do this:
Object.prototype.size = function(){
var length = 0;
for(var i in this){
if(this.hasOwnProperty(i)){
length++;
}
}
return this;
}
But the problem is that It extends all objects. What I'd like to do is have this:
var MyNameSpace = function(){
};
MyNameSpace.Object.prototype.size = function(){
var length = 0;
for(var i in this){
if(this.hasOwnProperty(i)){
length++;
}
}
return this;
}
That way I would only be extending the native objects in the scope of my global object.
any suggestions would be great thanks
Update:
In response to a few comments I'm adding more code to clarify what I'm trying to do.
I think i may have not phrased my question correctly, or maybe my thinking is incorrect, but what i'd like to be able to do is this:
var my = new MyNameSpace();
var my.name = {firstName : 'Hello', lastName : 'World'};
var nameCount = my.name.size(); // 2
the code you provided will allow me to get the size of each MyNameSpace object I create, but not the object literals that are properties of the MyNameSpace object
You could use "pseudo-classical" inheritance style to achieve it:
var MyNameSpace = function() {
this.v1 = null;
this.v2 = null;
}
MyNameSpace.prototype.size = function() {
var length = 0;
for(var i in this){
if(this.hasOwnProperty(i)){
length++;
}
}
return this;
}
var my = new MyNameSpace(); // create new object based on MyNameSpace
my.size(); // length would be 2
What you define on a function object's prototype would be inherited by all the function objects created via new operator.
Updated code, according to your added requirements,
var obj = {};
var MyNameSpace = function(props) {
for(var name in props) {
this[name] = props[name];
}
}
MyNameSpace.prototype.size = function() {
var length = 0;
for(var i in this){
if(this.hasOwnProperty(i)){
length++;
}
}
return this;
}
obj.name = new MyNameSpace({firstName : 'Hello', lastName : 'World'});
obj.name.size(); // length would be 2
In your code
var my = new MyNameSpace();
var my.name = {firstName : 'Hello', lastName : 'World'};
var nameCount = my.name.size(); // 2
my.name is obviously traversable from my, but the opposite is not true. That means that properties of my cannot be accessed from my.name, and my is nowhere to be found in the prototype chain of my.name. If you don't want to inherit directly from MyNameSpace you have to explicitly "hang on" whatever functions you would like to inherit.
You could do
my.name.size = my.size;
alternatively (without having to instantiate MyNameSpace):
my.name.size = MyNameSpace.prototype.size;
if you have only few functions to "inherit". Or you could define an inherit function in MyNameSpace as follows:
MyNameSpace.prototype.addToNameSpace = function(obj) {
obj.size = this.size;
// obj.propertyI = this.propertyI, etc.
}
Note that I don't use for..in here as that would add the addToNameSpace function as well.
Hope this helps