Creating an array of other objects in javascript? - javascript

Is something like this possible:
function FooClass()
{
var barsArray=new Array();
var index=0;
function addBar()
{
barsArray[index]=new BarClass(index);
}
}
function BarClass()
{
var myIndex;
function BarClass(index)
{
myIndex=index;
}
}

I'm inferring that you want to have a Foo object, and that Foo object should contain an array of Bar objects. Each Bar object should know its array index within its parent Foo object.
If that is an accurate description, then try this:
function BarClass(idx) {
this.myIndex = idx;
}
function FooClass(howMany) {
this.barsArray = [];
for (var x = 0; x < howMany; x++) {
this.barsArray[x] = new BarClass(x);
}
}
var foo = new FooClass(5);
// foo.barsArray[0].myIndex === 0
// foo.barsArray[1].myIndex === 1
// foo.barsArray[2].myIndex === 2
// foo.barsArray[3].myIndex === 3
// foo.barsArray[4].myIndex === 4
// foo.constructor === 'FooClass'
// foo.barsArray[0].constructor === 'BarClass'
Good luck!

Not quite (actually it compiles, but probably doesn't do what you intended).
I'm assuming you want to create a FooClass class with an addBar method that appends a BarClass object to it's barsArray member.
The addBar function is just a local variable inside the FooClass function/constructor. To make it accessible from outside the constructor, you need to assign it to this.addBar. Other than remembering to increment index, that's all you would need to change in FooClass.
For the BarClass class, remember that a "class" is really just a constructor function. You don't need to (and can't) a separate constructor. BarClass would just be a single function that takes an index and assigns it to this.myIndex.
function FooClass()
{
// use this.barsArray = [], etc if you want them to be publically available
var barsArray=[]; // It's usually better to use "[]" instead of "new Array()"
var index=0;
this.addBar = function() {
barsArray[index]=new BarClass(index);
index++;
}
}
function BarClass(index)
{
this.myIndex=index;
}
If you change barsArray and index to be properties instead of local variables ("this.barsArray = [];" and "this.index = 0"), you can put addBar in FooClass.prototype and there will only be one instance of the function:
function FooClass()
{
this.barsArray=[];
this.index=0;
}
FooClass.prototype.addBar = function() {
this.barsArray[this.index]=new BarClass(this.index);
this.index++;
};

Related

How to define a new class extending standard javascript class like Array?

It is my understanding that the "standard" way to define a new ClassB extending ClassA is as following:
function ClassA() {
this.a = {}; // ClassA's instance member.
}
ClassA.prototype.meth1 = function () { .. } // ClassA's method, shared by all instance.
function ClassB() {}
ClassB.prototype = new ClassA() // <== "standard" way to extend
ClassB.prototype.meth2 = function () {...} // ClassB's method
When I try to define a new class ArrayX like following:
function ArrayX() {
}
ArrayX.prototype = new Array()
ArrayX.prototype.removeDup = function removeDup() {
var o = [];
for(var j=0; j<this.length; j++) {
if(notExist(this[j])
o.push(this[j])
}
return o
function notExist(itm) {
for(var j=0; j<o.length; j++) {
if(o[j]===itm)return false
}
return true;
}
var x = new ArrayX();
console.log(x.length) // returns 0. Good
console.log(x) // returns []. Good
x[0] = 0;
console.log(x); // returns []. No good. I expect x should have one element.
(new ArrayX([1,1,2,3,3])).removeDup() // I expect returns [1,2,3]
I know I can define the function-removeDup in following way:
Array.prototype.removeDup = function removeDup() { ...}
However, I just want to define a new class extending some standard javascript class like Array, or, even the DOM classes.
So, how to define a new class extending standard javascript class like Array?
no need to create a very own class:
Array.prototype.myFunction = function(){
//your custom code
}
By referring link#1, link#2 & link#3, I try this, it works as I expected.
function ArrayX() {
// Array.apply(this, arguments)
// calling Array() has same effect as new Array() according to
// [link#3]
// It is no good here.
this.push.apply(this, arguments); // <-- this works OK. Suggested by link#2
debugger; // Now, `this` has array of value [1, 1, 2, 3, 3], which is
// found in arguments when running new ArrayX(1,1,2,3,3);
// Good.
}
ArrayX.prototype = new Array(); // Suggested by link#1
ArrayX.prototype.removeDup = function removeDup() {
var o = [];
for(var j=0; j<this.length; j++) {
if(notExist(this[j]))
o.push(this[j])
}
return o
function notExist(itm) {
for(var j=0; j<o.length; j++)
if(o[j]===itm)return false
}
return true;
}
var x = new ArrayX(1,1,2,3,3); // x is now [1,1,2,3,3]. Good
console.log(x.length) // 5 Good
var y = x.removeDup(); // y is [1,2,3]. Good
console.log(y);

JavaScript Dynamic naming with argument of function.

I have been looking around for an answer to this but in vain.
I have a function which takes a table name as an argument. but this name can be an object.
loadDataFromServer = function(dataTable) {
//data fetch code ...
datadump[dataTable] = response.getDataTable();
}
loadDataFromServer(['gchart']['data'])
The problem is I need to store the data in a variable datadump.gchart.data but the "gchart.data" part needs to be determined upon calling the function, not hard coded in it.
my problem lies in the fact that
datadump[['gchart']['data']] is not the same as
datadump['gchart']['data'] (which is the same as datadump.gchart.data)
Does anybody here know a good way to do this? If the input was simply gchart_data, this would easily work, but the functions needs to able to handle it even if it needed to assign its data to blabla.blibli.bloebloe.stuff.
thanks in advance
I think what you're looking for is this:
function (result) {
datadump = {};
datadump.gchart = {};
datadump.gchart.data = result.gchart.data;
// or
datadump.gchart = {
data: result.gchart.data
};
}
It's a little bit strange to it like this though. Do you absolutely need the gchart in your datadump?
Assigning to a random depth like blabla.blibli.bloebloe.stuff is not easily done.
You could flatten like: obj["blabla.blibli.bloebloe.stuff"] = {};
Or you could write a recursive merge, like:
var a, b, c;
a = { foo: { ipsum: "lorem" } };
b = { bar: {}, foo: { abc: "def" } };
c = recursive_merge(a, b); // { foo: { ipsum: "lorem", abc: "def" }, bar: {} };
Have you function take a list of strings and iterate over them to recursively access (and, if necessary, create) properties of datadump. I use arguments here to use the list of arguments itself, but you could also just use a single argument that is an array of strings.
var loadDataFromServer = function() {
var currObj = datadump;
// iterate over the list of property names
for(var i=0; i<arguments.length - 1; ++i) {
var nextName = arguments[i];
// if the object doesn't have this property, make it
if(currObj[nextName] == undefined) {
currObj[nextName] = {};
}
// use currObj's property as the new `currObj`
currObj = currObj[nextName];
}
// load data into the final named property
currObj[arguments[i]] = response.getDataTable();
}
loadDataFromServer('gchart', 'data');

trying to implement an array within an array of of objects

In Google Apps JS. I would like to implement an array of objects, each with properties and methods. One of the properties needs to be an array of objects and I would like to be able to access this array by using methods in the parent array.
So far my best efforts is:
function myFunction () {
var teamNo = 3;
var allNames =["n1","n2","n3","n4"] ;
var createnames = function () {
var names = [];
for ( var j = 0; j <=3 ; j ++) {
(function (j) {
var localNames = ["local1-names"+j,"local2-names"+j];
names[j] = (function (player){
return {
namArr: localNames,
name: allNames[j],
addName: (function (player){
localNames.push(player);
}) (player),
team: teamNo
};
});
}) (j);
}
return names;
}
var myname = createnames();
var foo = myname[0]().namArr;
var foo1 = myname[1]().namArr;
myname[1]().addName("added");
var foo2 = myname[1]().namArr;
var foo3 = myname[2]().namArr;
var debug = true;
}
As soo as I add the code to implement the sub array I get a runtime error saying that addName does not exist.
You're invoking this immediately:
addName: (function (player) {
localNames.push(player);
})(player)
instead of assigning it:
addName: function (player) {
localNames.push(player);
}
Also, each names[] function takes a player, and so does the addPlayer() function, making the names[] parameter unreachable. If you're not going to pass anything to the names[] functions, then remove the parameter.
And I'd suggest using named functions instead of inlined IIFEs.

JavaScript: List global variables in IE

I'm trying to get the instance name of my class.
The way I do this is I loop through all global objects and compare it with the this pointer.
It works in Chrome and FF, but in IE, it doesn't. The problem seems to be the global variables don't seem to be in window.
How can I loop through the global variables in IE ?
PS: I know it only works as long as there is only one instance, and I don't want to pass the instance's name as a parameter.
function myClass()
{
this.myName = function ()
{
// search through the global object for a name that resolves to this object
for (var name in this.global)
{
if (this.global[name] == this)
return name
}
}
}
function myClass_chrome()
{
this.myName = function ()
{
// search through the global object for a name that resolves to this object
for (var name in window)
{
if (window[name] == this)
return name ;
}
} ;
}
// store the global object, which can be referred to as this at the top level, in a
// property on our prototype, so we can refer to it in our object's methods
myClass.prototype.global = this
//myClass_IE.prototype.global = this
// create a global variable referring to an object
// var myVar = new myClass()
var myVar = new myClass_chrome()
//var myVar = new myClass_IE()
alert(myVar.myName() );// returns "myVar"
Better idea, solved:
function myClass_IE()
{
this.myName = function ()
{
// search through the global object for a name that resolves to this object
for (var i = 0; i < document.scripts.length; i++)
{
var src = document.scripts[i].innerHTML ;
//document.write('script ' + i + ' = ' + document.scripts[i].innerHTML )
var idents = src.replace(/\W/g, ' ').replace(/(function|if|for|while|true|false|null|typeof|var|new|try|catch|return|prototype|this)/g, '').split(' ');
for(var j = 0; j < idents.length; j++)
{
//var iden = String(idents[j]).trim();
var iden = String(idents[j]);
if (window[iden] == this)
{
// http://mcarthurgfx.com/blog/article/iterating-global-variables-in-internet-explorer
// http://blog.stevenlevithan.com/archives/faster-trim-javascript
return iden;
}
}
}
}
}
function myClass()
{
this.myName = function ()
{
// search through the global object for a name that resolves to this object
for (var name in this.global)
{
if (this.global[name] == this)
return name
}
}
}
function myClass_chrome()
{
this.myName = function ()
{
// search through the global object for a name that resolves to this object
for (var name in window)
{
if (window[name] == this)
return name ;
}
} ;
}
// store the global object, which can be referred to as this at the top level, in a
// property on our prototype, so we can refer to it in our object's methods
myClass.prototype.global = this
//myClass_IE.prototype.global = this
// create a global variable referring to an object
// var myVar = new myClass()
//var myVar = new myClass_chrome()
var myVar = new myClass_IE()
alert(myVar.myName() );// returns "myVar"
In IE, it global variables aren't enumerable unless you explicitly define them as properties of the window object.
var noEnum = true; // won't show up in a for...in loop
window.willEnum = true; // will show up in a for...in loop
Clearly, you found your own solution but it will work for inlined scripts only - although this could be extended to external scripts using ajax to fetch the contents from the cache (or from the server if they're not cached).

JavaScript Object Id

Do JavaScript objects/variables have some sort of unique identifier? Like Ruby has object_id. I don't mean the DOM id attribute, but rather some sort of memory address of some kind.
If you want to lookup/associate an object with a unique identifier without modifying the underlying object, you can use a WeakMap:
// Note that object must be an object or array,
// NOT a primitive value like string, number, etc.
var objIdMap=new WeakMap, objectCount = 0;
function objectId(object){
if (!objIdMap.has(object)) objIdMap.set(object,++objectCount);
return objIdMap.get(object);
}
var o1={}, o2={}, o3={a:1}, o4={a:1};
console.log( objectId(o1) ) // 1
console.log( objectId(o2) ) // 2
console.log( objectId(o1) ) // 1
console.log( objectId(o3) ) // 3
console.log( objectId(o4) ) // 4
console.log( objectId(o3) ) // 3
Using a WeakMap instead of Map ensures that the objects can still be garbage-collected.
No, objects don't have a built in identifier, though you can add one by modifying the object prototype. Here's an example of how you might do that:
(function() {
var id = 0;
function generateId() { return id++; };
Object.prototype.id = function() {
var newId = generateId();
this.id = function() { return newId; };
return newId;
};
})();
That said, in general modifying the object prototype is considered very bad practice. I would instead recommend that you manually assign an id to objects as needed or use a touch function as others have suggested.
Actually, you don't need to modify the object prototype. The following should work to 'obtain' unique ids for any object, efficiently enough.
var __next_objid=1;
function objectId(obj) {
if (obj==null) return null;
if (obj.__obj_id==null) obj.__obj_id=__next_objid++;
return obj.__obj_id;
}
I've just come across this, and thought I'd add my thoughts. As others have suggested, I'd recommend manually adding IDs, but if you really want something close to what you've described, you could use this:
var objectId = (function () {
var allObjects = [];
var f = function(obj) {
if (allObjects.indexOf(obj) === -1) {
allObjects.push(obj);
}
return allObjects.indexOf(obj);
}
f.clear = function() {
allObjects = [];
};
return f;
})();
You can get any object's ID by calling objectId(obj). Then if you want the id to be a property of the object, you can either extend the prototype:
Object.prototype.id = function () {
return objectId(this);
}
or you can manually add an ID to each object by adding a similar function as a method.
The major caveat is that this will prevent the garbage collector from destroying objects when they drop out of scope... they will never drop out of the scope of the allObjects array, so you might find memory leaks are an issue. If your set on using this method, you should do so for debugging purpose only. When needed, you can do objectId.clear() to clear the allObjects and let the GC do its job (but from that point the object ids will all be reset).
const log = console.log;
function* generateId() {
for(let i = 0; ; ++i) {
yield i;
}
}
const idGenerator = generateId();
const ObjectWithId = new Proxy(Object, {
construct(target, args) {
const instance = Reflect.construct(target, args);
instance['id'] = idGenerator.next().value;
return instance;
}
})
const myObject = new ObjectWithId({
name: '##NativeObject'
});
log(myObject.id);

Categories