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.
Related
I created a class in JavaScript as follows:
class TreeMatching
{
constructor()
{
this.thresholdPoints=0;
this.neighborWeight = 0.4;
this.totalFrequency = 0.0;
this.listSeq = [];
this.listFreq = [];
this.mapScore = new Object();
this.tree = new Trie();
}
createTree()
{
var list_Dictionary;
var loadWordList = $.get("../wordFrequencyTop5000.txt", function(data)
{
list_Dictionary = data.split("\n");
});
loadWordList.done(function()
{
for(var i=0;i<list_Dictionary.length;i++)
{
var string = list_Dictionary[i];
this.tree.insert(string); //<-- Cannot read property 'insert' of undefined
}
});
}
}
which is supposed to call the insert method in class Trie as follows:
class Trie
{
constructor()
{
this.count=1;
this.root = new TrieNode();
}
insert(word)
{
var children = new Object();
for(var i=0; i<word.length(); i++){
var c = word.charAt(i);
var t;
if(children[c]){
t = children[c];
}else{
t = new TrieNode(c);
children.put(c, t);
}
children = t.children;
//set leaf node
if(i==word.length()-1)
t.isLeaf = true;
}
}
}
However, the line of code where the error is marked, the outer function's this value, is not having properties tree, mapScore, etc.
Is there a way that I can access those values from the inner callback function?
Thanks
look at 'this' - you will have to define local variable to maintain reference to "this" inside the call, as described in the link.
createTree()
{
var self = this;
var list_Dictionary;
var loadWordList = $.get("../wordFrequencyTop5000.txt", function(data)
{
list_Dictionary = data.split("\n");
});
loadWordList.done(function()
{
for(var i=0;i<list_Dictionary.length;i++)
{
var string = list_Dictionary[i];
self.tree.insert(string); //<-- Now you should be able to do it
}
});
}
'this' in the inner anonymous has different scope. Try to use the advantage of closer in JS which will get access to the function caller scope.
var that = this;
loadWordList.done(function() {
for(var i=0;i<list_Dictionary.length;i++)
{
var string = list_Dictionary[i];
that.tree.insert(string); // 'that' will hold 'this' in the right scope
}
});
The anonymous function inside loadWordlist.done creates a new scope with an new context.
if you want to keep the old context you can use the ES2015 arrow function:
loadWordList.done(() => {
//code here
);
or make a var inside createTree() like this:
var that = this;
and then inside the loadWordList callback you can refer to the right context using:
that.tree.insert(string);
I personally prefer the arrow function because 'that' is a lousy choice for a var name. And since your using the ES2015 classes browser support must not be an issue.
I would like to store function pointers in an Array and then execute all of them in a foreach loop.
var array = new Array();
array['foo'] = function() { doFoo(); };
array['bar'] = function() { doBar(); };
How do I iterate and execute all functions in array?
First, if you really want to use non-numeric property names, you don't need an array:
var obj = {};
obj["foo"] = function() { doFoo(); }
obj["bar"] = function() { doBar(); }
To iterate and call the functions:
for (var k in obj) {
obj[k]();
}
To be pedantic, it's usually considered a good idea to make sure you're not running into unexpected properties inherited from the prototype:
for (var k in obj) {
if (obj.hasOwnProperty(l))
obj[k]();
}
I am trying to set some variable to an object. But i want it to be set like the code below
is there a way to set a variable like this?
myObject = {};
myObject.save = function (var) {
console.log(var);
}
myObject.users.save(); // must output 'users';
myObject.fruits.save(); // output fruit;
the save method is just an example method. it means that i need to chain a method on the variable string.
i trying to achieve something like that.
any ideas how to achieve that?
thanks
You can create a List class for your users and fruits lists, and provide regular list methods like add, remove, size and etc. to make it actually like a list class, and define your save method as a prototype method:
var List = (function(){
function List(listType){
this.listType = listType;
this._list = [];
}
List.prototype.add = function(item){
this._list.push(item);
};
List.prototype.size = function(item){
return this._list.length;
};
List.prototype.save = function(item){
console.log(this.listType);
};
return List;
})();
then you can use it in your object like:
var myObject = {};
myObject.users = new List("users");
myObject.fruits = new List("fruits");
now you can actually call those two lines of code:
myObject.users.save(); // output 'users';
myObject.fruits.save(); // output 'fruits';
and you can also define a save method for myObject and actually call the lists save method:
myObject.save = function(listType){
if(myObject[listType] instanceof List){
myObject[listType].save();
}
else{
console.log("there is no such a list named : " + listType);
}
};
and call it like:
myObject.save("users");
myObject.save("fruits");
You can do like
var obj = {
users: {
save: function () {
console.log('Users');
}
},
fruits: {
save: function () {
console.log('Fruits');
}
},
}
(or)
var obj = {};
obj.users = {};
obj.users.save = function () {
console.log('Users');
};
obj.fruits = {};
obj.fruits.save = function () {
console.log('Fruits');
};
I have a function that looks like this:
var tempFun = function() {
return 'something';
}
tempFun.priority = 100;
Now I'm pushing it to an array and binding another object to it in the process like this:
var funArray = [];
var newObj = {};
funArray.push( tempFun.bind(newObj) );
and after this, I would like to acces the function's property like this:
funArray[0].priority
but it returns undefined. Is there some way to preserve the property on the function while binding a new object to it?
No, but you could write a function to do this yourself;
Function.prototype.bindAndCopy = function () {
var ret = this.bind.apply(this, arguments);
for (var x in this) {
if (this.hasOwnProperty(x)) {
ret[x] = this[x];
}
}
return ret;
};
... which you could then use via;
var funArray = [];
var newObj = {};
funArray.push( tempFun.bindAndCopy(newObj) );
No. Bind returns a new function, which "wraps" around the original one. All you can do is copy the properties on this new function:
var boundFun = tempFun.bind(newObj)
boundFun.priority = tempFun.priority;
funArray.push( boundFun );
If you want the properties to be in sync (changes in one visible on the other) you can do:
Object.defineProperty(boundFun, 'priority', {
get : function () { return tempFun.priority; },
set : function (val) { tempFun.priority = val; }
});
From MDN:
The bind() method creates a new function that, when called, has its
this keyword set to the provided value, with a given sequence of
arguments preceding any provided when the new function is called.
Hence, .bind() won't be useful for what you're trying to achieve. Besides using jQuery mappers or rewriting your code to use .prototype, a solution that I can think of is:
var obj = {};
for (var i in tempFun) {
if (tempFun.hasOwnProperty(i)) obj[i] = tempFun[i];
}
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++;
};