Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript recursive function reference this

I'm trying to create a function that will generate a tree like structure such that each item contains a reference to it's parent item.

I have a function that calls itself when creating the children but am having a tough time with it, it seems that once it is called from within itself this still refers to the top level item rather than the current one.

Logging to console what the item is I can see that parent always refers to the first item in the chain (or is absent) when deeper than the first level. It creates the tree, but references to parent are lost for items besides the first.

var Item = function (item, parent) {
  console.log('item is :' + item.name);
  this.parent = parent;
  console.log('parent is: ' + parent);
  var fields = _.union(_.keys(item), _.keys(this.parent));
  _.each(_.without(fields, ['parent','children']), function (prop) {
    this[prop] = angular.isDefined(item[prop]) ? item[prop] : this.parent[prop];
  }, this);

  this.children = [];
  if (item.children) {
    this.children = _.map(item.children, function (child) {
      console.log('this is : ' + this);
      return new Item(child, this)
    }, this);
  }
};

var tree = new Item(root, {});

Having a bit of trouble getting a fiddle going, but here is some sample data:

var root = JSON.parse('{"id":"1","name":"root item","root":"1","lft":"1","rgt":"22","level":"1","type":
"category","parent_id":"1","deadline":null,
"children":[
{"id":"2","name":"item 1","root":"1","lft":"14","rgt":"15","level":"2","type":"category","parent_id":"1"}, 
{"id":"6","name":"item 2","root":"1","lft":"16","rgt":"19","level":"2","type":"category","parent_id":"1"}, 
{"id":"10","name":"item 3","root":"1","lft":"20","rgt":"21","level":"2","type":"item","parent_id":"1"}]}');
like image 434
JPR Avatar asked Dec 12 '13 03:12

JPR


People also ask

How do you write a recursive function in JavaScript?

The syntax for recursive function is: function recurse() { // function code recurse(); // function code } recurse();

Can a JavaScript function call itself?

A function can refer to and call itself.

How do you call a function recursively?

Recursion using mutual function call: (Indirect way) Indirect calling. Though least practical, a function [funA()] can call another function [funB()] which in turn calls [funA()] the former function. In this case, both the functions should have the base case.

Can we use call by reference in recursion?

Yes, it has to be pass by reference.


2 Answers

The problem is in your usage of the _.without method. The elements to exclude are passed as a variable number of arguments, not as an array.

Wrong usage:

_.without(['a','b'],['a'])

results in ['a', 'b'] (not what you want)

Whereas:

_.without(['a','b'],'a')

yields your expected result: ['b']

Here's an updated fiddle with the fix.

Note: to avoid the cyclic reference, I print out the parent.id instead of parent in the "Result" output.

like image 56
sinelaw Avatar answered Oct 17 '22 02:10

sinelaw


It does the job for me. I simplify the code a bit and added the grandchild item. Have a look: http://jsfiddle.net/7QYQL/1/

var grandchild = {};
grandchild.name = 'grandchild';
var child = {};
child.name = 'child';
child.children = [];
child.children[0] = grandchild;
var root = {};
root.name = 'root';
root.children = [];
root.children[0] = child;

The problem was _.without() which takes a list rather then an array as a second parameter.

_.without(fields, 'parent','children')

This one works: http://jsfiddle.net/eRbhm/13/

like image 1
Arek S Avatar answered Oct 17 '22 02:10

Arek S