Collecting all object which created with a constructor? - javascript

Is there any simple way of getting all objects which created with a constructor function
var ObjectConstructor = function(value){
this.value = value;
this.arr = [];
this.someMethod= function () {
//do something
}
};
$.each($('.someClass'), function () {
var o = new ObjectConstructor (this);
o.someMethod();
})
I created so many objects with the help of this pattern. Now I need to collect all of them, somewhere in the process.
My solution is creating a global object outside of constructor
var allObjects = [];
and adding objects one by one to this array while generating them inside constructor function
allObjects.push(this)
Final Code :
var allObjects = [];
var ObjectConstructor = function(value){
this.value = value;
this.arr = [];
this.someMethod= function () {
//do something
}
allObjects.push(this)
};
$.each($('.someClass'), function () {
var o = new ObjectConstructor (this);
o.someMethod();
})
Now I can use allObjects array.
My question: Is my solution OK? Or is there any better approach for this. Thank you.

My solution is creating a global object outside of constructor var allObjects = [];
Yes, that's basically how to do this. However, you need to notice that this could be a memory leak, when you forget to remove objects from the array that are no more needed.
Is there any better approach for this.
That depends on what you think to need this for.

Related

Javascript Arrays as an object field

I am running into a problem with using an array as a Javascript field.
var Object = function () {
var admins = [];
this.addAdmin = function(admin){
this.admins.push(admin)
}
}
Normally I would expect admin to be pushed into the array admins but instead I get a 'cannot read property 'push' of undefined'.
If I'm not mistaken when I initialized the Object with new Object(), admins = []; should initialize the array. Is this a limitation of Javascript?
Thank you in advance.
var array creates a local variable. It does not create a property on the object.
You need:
this.admins = [];
or
admins.push(admin) /* without this */
In your function admins is a local variable to the function. You need to declare admins as a property on the instance.
function Obj(){
this.admins = [];
}
Obj.prototype.addAdmin = function(admin){
this.admins.push(admin);
}
obj = new Obj();
obj.addAdmin('tester');
Also, because Object is the global base object, don't create functions or objects named Object.
I suspect you've gotten confused (which is easy :-) ) because you've seen code like this:
class Obj {
admins = [];
addAdmin(admin) {
this.admins.push(admin);
}
}
That uses the modern class and class fields syntax to puts an admins property on the object constructed via new Obj. (Note there's no var before admins = [];.) But in your code, you've used the older function-based syntax. Within your function, var admins = []; just creates a local variable, not a property.
I'd suggest that if you want to create constructor functions, using the new class syntax above is the simpler, more powerful way to do that. If you want to use the older syntax, though, other answers have shown how, but for completeness either make admins a property of the object:
let Obj = function() {
this.admins = []; // ***
this.addAdmin = function(admin){
this.admins.push(admin)
};
};
or perhaps with addAdmin on the prototype:
let Obj = function() {
this.admins = []; // ***
};
Obj.prototype.addAdmin = function(admin){
this.admins.push(admin)
};
or use the fact addAdmins closes over the call to Obj, and thus the local admins:
let Obj = function() {
const admins = [];
this.addAdmin = function(admin){
admins.push(admin) // <=== No `this.` here, you want to close over the
// `admins` local
};
};
I am assumming Object is a placeholder, because it is a reserved keyword.
What is happening is, your variable var admins = []; is created locally and can noot be accesed with the this. as a result when you set the value in this.admins.push(admin) the admins there is undefined. you should modify your function to read this way
var Obj = function () {
this.admins = [];
this.addAdmin = function (admin) {
this.admins.push(admin);
};
};
const object = new Obj();
object.addAdmin(1);
you should not omit the this keyword like this(no pun intended) if you plan to new the function. Stick to the code above.
var Obj = function () {
var admins = [];
this.addAdmin = function (admin) {
admins.push(admin);
};
};
const object = new Obj();
console.log(object)

Javascript object definition

Out the following two ways, which format for defining object is good considering performance and usage:
//Object created with public members defined using this.
var object1 = function () {
var private_i = null;
this.public_j = null;
//public function
this.public_func = function () {
}
}
OR
//Object created with public members defined using return patterns.
var object2 = function () {
var private_i = null,
public_j = null,
//private function will be exposed from return statement.
_public_func = function () {
};
return {
public_func : _public_func
};
}
The difference between the two relates to inheritance and usage. Your object2 always creates objects directly backed by Object.prototype and doesn't require use of the new keyword; your object1 creates object backed by object1.prototype (which is in turn backed by Object.prototype) and does require use of new.
Neither is really "better" in any objective way, they are just two different ways of using JavaScript, which will have fundamentally the same performance. The first one is much more common, the second one is advocated by a small but vocal minority within the JavaScript community.
The object1 example is more typically written like this:
function Object1() {
var private_i = null;
this.public_j = null;
//public function
this.public_func = function () {
};
}
Note that the first letter in such functions is capitalized (by overwhelming convention).
The prototype thing comes into it if you're going to have functions that don't need access to private_i: You could put those on the object that will be assigned to new objects created via new Object1 like so:
function Object1() {
var private_i = null;
this.public_j = null;
//public function
this.public_func = function () {
};
}
Object1.prototype.someOtherFunction = function() {
// Doesn't use `private_i`
};
You can also use prototypes with your object2, like so:
//Object created with public members defined using return patterns.
var object2Prototype = {
someOtherFunction: function() {
// Doesn't need private_i
};
};
var object2 = function () {
var private_i = null,
public_j = null,
//private function will be exposed from return statement.
_public_func = function () {
};
var obj = Object.create(object2Prototype);
obj.public_func = _public_func;
return obj;
};

JavaScript class to populate object

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 })
}
}

JavaScript Class Best Practice?

I'm currently looking into different patterns for building classes in JavaScript. But no matther what pattern I see, there are still some things I am not really sure about.
var ItemManager = (function()
{
var p = function()
{
this.items= [];
};
p.prototype.addItem = function(item)
{
var self = this;
self.items.push(item);
};
return p;
}());
I create the simple class ItemManager, this class got the function addItem for adding any item to the collection. Now I don't really want the variable items, which represents the collection, to be public, this variable should be private, but I don't see any possible way to use a prototyped method to access private variables.
So what's the best practice in this case? Simply don't use private variables?
var ItemManager = function() {
var items = [];
return {
addItem : function(item) {
items.push(item);
},
removeItem : function() {
return items.pop();
}
}
};
var myItemManager = new ItemManager();
items variable becomes hidden after the execution of ItemManager function, but addItem and removeItem still share the access to items. See the Douglas Crockford's article on private variables in JavaScript for further investigation.
There are several ways to have private variables:
Closures, as in aga's example, which uses the Revealing Module Pattern. If you're using ES6 classes, you can hide private data in the constructor, though it looks pretty ugly to me.
[ES6] Symbols
[ES6] WeakMap
I favor Symbols, though they can still be found using reflection (i.e. not completely private). Example:
var Person = (function() {
var nameSymbol = Symbol('name');
​
function Person(name) {
this[nameSymbol] = name;
}
​
Person.prototype.getName = function() {
return this[nameSymbol];
};
​
return Person;
}());
So it's possible to have (reasonably) private variables, but unfortunately none of the solutions are as elegant as you'd like.
as GoldenerAal mentioned, they are not called classes, but functions
you have
var ItemManager = function (){
..
...
...
};
you could have:
function ItemManager(){
this.items = [];
function addItem(item){
...
};
};
you can then create an instance of ItemManager, only when you need to :
var itemManager = new ItemManager();
itemManager.addItem(<something here>);
http://javascript.crockford.com/private.html
variables inside a function only have the scope of that function, that variable is not a global variable (static variable).

function object inheritance using jquery's extend

I'm trying to simulate inheritance using jquery extend but as far as I could test, it works only with objects.
What I'm trying to accomplish is:
var baseDefinition = function() {
var self = this;
self.calc1 = function() {
return "something1";
}
self.calc2 = function() {
return "something2";
}
self.myObject = {
propA = 100;
propB = 200;
};
}
var derivedDefinition = function() {
var self = this;
self.calc2 = function() {
return "something different from base";
}
self.myObject = {
propB = 400;
};
}
var instance = $.extend(true, {}, baseDefinition, derivedDefinition);
So I would hope to create a new instance from base definition where the derived definitions would be applied to the base ones but neither definitions would be "touched". Is it possible?
I was hoping to avoid any prototype so basicaly I would like to call instance.calc1 or instance.calc2 without knowing wether it was overriten or not.
Edit:
In my example I didn't include any object properties which was what led me to use jquery's extend function. Although both answers solve inner functions "inheritance", it doesn't (obviously) merge object properties like extend does. As a possible solution I'm thinking after I create my instance to loop through the properties of the instance and apply jquery's extend on them. Although this seems inefficient to me, I don't know if you can advise me on another course of action.
JQuery extend does not create an inheritance hierarchy, so changes you make to base definition AFTER you extend would not be reflected in derived definition. Here's how you can extend the base definition in a way that does reflect later changes down the inheritance hierarchy using Javascript prototypal inheritance:
var baseDefinition = function() {};
baseDefinition.prototype.calc1 = function() {
return "something1";
};
baseDefinition.prototype.calc2 = function() {
return "something2";
};
var derivedDefinition = function() {};
derivedDefinition.prototype = Object.create(baseDefinition.prototype);
derivedDefinition.prototype.calc2 = function() {
return "something different from base";
};
var instance = new derivedDefinition();
instance.calc1(); // something1
instance.calc2(); // something different from base
$.extend only works on already existing objects, not on function which will instantiate objects in the (far?) future:
var instance = $.extend(true, {}, new baseDefinition(), new derivedDefinition());
However, you could of course design an extend function that works for constructors and that returns a function:
function extendConstr() {
var fns = arguments;
return function newConstr(){
var self = {};
for (var i=0; i<fns.length; i++)
fns[i].apply(self, arguments);
return self;
}
}
var extendedFunction = extendConstr(baseDefinition, derivedDefinition);
var instance = extendedFunction();
console.log(instance); // has `calc1` and overwritten `calc2`
Btw, without an extend function you could've done that already manually in the derived constructor:
function derivedDefinition() {
baseDefinition.call(this/*, arguments */);
this.calc2 = function() {
return "something different from base";
}
}
console.log(new derivedDefinition) // has a `calc1` as well

Categories

Resources