I have this recursive function that is suppose to go through a JSON object to find all the subgroups. Here is what I have:
var subgroupIds = [];
this.getSubGroups = function (groupId) {
this.getGroups("groupId="+groupId, function(groups) {
if ($.isEmptyObject(groups)) {
return subgroupIds;
} else {
$.each(groups, function(index,group) {
subgroupIds.push(group.id);
this.getSubGroups(group.id);
});
}
});
}
...where getGroups is an asynchronous function that returns all the groups.
My problem is when it gets to the recursive call, I get the error that says:
Uncaught TypeError: Object #<Object> has no method 'getSubGroups'
I'm guessing it's a scope issue but I can't figure out what's wrong with it. Any ideas?
EDIT:
As Bergi pointed out, I need to have a callback. This is what I have now:
var subgroupIds = [];
var that = this;
this.getSubGroups = function (groupId,callback) {
this.getGroups("groupId="+groupId, function(groups) {
if ($.isEmptyObject(groups)) {
return;
} else {
$.each(groups, function(index,group) {
subgroupIds.push(group.id);
callback(group.id);
that.getSubGroups(group.id);
});
}
});
}
The trouble now is when I call the callback, it says the function is undefined.
Ultimately, I want to return an array of sub group.id's. I'm not sure how to get there...
This is because thi inner function, defined in each
does not belong to this
instance of your class/object, isntead it refers to the callback function itself. To bypass this problem, at the object constructor, I put the folowing:
function SimpleClass() {
var _this = this; //Private property, will be shared in all functions defined in the class
this.value = "Hello";
this.value2 = " world!";
function say() { //private function - use _this (this means something else here)
return _this.say; //Gets property of the object
}
this.say = function() { //Public function - use this
alert(this.value+say()); //Here, we can use both this and _this
}
}
var _this = this;
var subgroupIds = [];
this.getSubGroups = function (groupId) {
this.getGroups("groupId="+groupId, function(groups) {
if ($.isEmptyObject(groups)) {
return subgroupIds;
} else {
$.each(groups, function(index,group) {
subgroupIds.push(group.id);
_this.getSubGroups(group.id);
});
}
});
}
Your this
is not the same this
as before. Perhaps save this
into a variable name more relevant to the object it's referencing (I'll use someObject
...) before your first getSubGroups
call, and then call someObject.getSubGroups
later.
var subgroupIds = [];
var someObject = this;
someObject.getSubGroups = function (groupId) {
this.getGroups("groupId="+groupId, function(groups) {
if ($.isEmptyObject(groups)) {
return subgroupIds;
} else {
$.each(groups, function(index,group) {
subgroupIds.push(group.id);
someObject.getSubGroups(group.id);
});
}
});
}
The reason why this happens is because your function is called from the $.each
implementation. I would refer to MDN docs of "this" for more details.
The inner this
refers to $.each
callback, you can do something like this:
var subgroupIds = [];
var self = this;
self.getSubGroups = function (groupId) {
self.getGroups("groupId="+groupId, function(groups) {
if ($.isEmptyObject(groups)) {
return subgroupIds;
} else {
$.each(groups, function(index,group) {
subgroupIds.push(group.id);
self.getSubGroups(group.id);
});
}
});
}
This is because this
is defined at a function level, and is bound to the item in the array you're iterating over for the inner function in this case. this
within the inner function does not refer to the same thing as this
within the outer function. You can get around this by setting var that = this;
on the outer level and referencing that
from within the inner function
var subgroupIds = [];
var that = this;
this.getSubGroups = function (groupId) {
this.getGroups("groupId="+groupId, function(groups) {
if ($.isEmptyObject(groups)) {
return subgroupIds;
} else {
$.each(groups, function(index,group) {
subgroupIds.push(group.id);
that.getSubGroups(group.id);
});
}
});
}
For more see How do closures work
And here for How this works in JS
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.