2013-02-28 4 views
1

Я пытаюсь построить иерархию (древовидную структуру) с помощью JavaScript. Для этого я написал класс Node, который представляет узел в дереве. Когда я извлекаю данные из базы данных, все они извлекаются должным образом (т. Е. Корневой узел имеет ParentId как null, он имеет 3 дочерних элемента, которые указывают на него как на родителя, а узлы-потомки также настроены правильно. .). Но когда я пытаюсь сопоставить их с моей моделью JavaScript, свойство корневого узла Children заканчивается undefined. Я не знаю, как это могло бы быть возможно, хотя во время выполнения, когда я выводил содержимое свойства Children в консоли, я вижу, что дочерние узлы добавляются к нему. Вот мой код:Массив сбрасывается до неопределенного после добавления элементов к нему

var Node = function (obj) { 
    var self = this; 
    var isDefined = obj != undefined; 

    self.hasChildren = function() { 
     return self.Children.length > 0; 
    }; 

    self.hasParent = function() { 
     var p = self.ParentId; 
     return !(p == null || p == undefined || p == 0); 
    }; 

    self.addChildren = function (objArray) { 
     if (!$.isArray(self.Children)) { 
      self.Children = []; 
     } 
     for (var i = 0; i < objArray.length; i++) { 
      self.addChild(objArray[i]); 
     } 
    }; 

    self.addChild = function (obj) { 
     if (obj instanceof Node) { 
      self.Children.push(obj); 
     } else { 
      var n = new Node(obj); 
      self.Children.push(n); 
     } 
    }; 

    self.removeChild = function (n) { 
     var index = self.Children.indexOf(n); 
     if (index > -1) { 
      self.Children.splice(index, 1); 
     } 
    }; 

    self.Id = isDefined ? obj.Id : null; 
    self.ParentId = isDefined ? obj.ParentId : null; 
    self.Name = isDefined ? obj.Name : ''; 
    self.Children = isDefined ? self.addChildren(obj.Children) : []; 
    self.TypeId = isDefined ? obj.TypeId : null; 
}; 

То, как я думал о методе addChildren, является то, что я передам сырой объект JSON, идущий от сервера в конструктор Node объекта, а затем в случае, если у него есть дети (которые по существу, имеют те же свойства, что и у родителя), будет называться addChildren, который, в свою очередь, создаст новый Node для каждого элемента. В конечном итоге дерево будет построено рекурсивно.

Так где же я ошибся? Почему свойство Children в конечном итоге составляет undefined?

+0

Покажите нам код, который вы используете для создания объекта Node, и код, вызывающий метод, в котором '.Children' не определен. – jfriend00

+0

@ Нуклеон, да, это намерение. Дети узла - всего лишь непосредственные дети, не все потомки. – Kassem

ответ

2
self.Children = isDefined ? self.addChildren(obj.Children) : []; 

Вы настраиваете себя. Дети равны возврату self.addChildren(). Эта функция не имеет возврата.

Вот несколько вещей, которые я бы рекомендовал

function Node(obj) { 
    // clean constructor moving function definitions to prototype 
    var self = this; 

    // ensure that we at least have an object passed in 
    obj = obj || {}; 

    // default values at the top 
    self.Id = null; 
    self.ParentId = null; 
    self.Name = ''; 
    self.Children = []; 
    self.TypeId = null; 

    // fold in data with $.extend, no need to specify each key manually 
    // third object is to overwrite any added Children as those need to be handled seperately 
    $.extend(self, obj, { Children : [] }); 

    // if we have children, add them using the addChildren method 
    if (typeof obj.Children !== undefined && $.isArray(obj.Children)) { 
     self.addChildren(obj.Children); 
    } 
} 

// using prototype to reduce memory footprint 
Node.prototype.hasChildren = function() { 
    return this.Children.length > 0; 
}; 

Node.prototype.hasParent = function() { 
    var p = this.ParentId; 
    return !(p == null || p == undefined || p == 0); 
}; 

Node.prototype.addChildren = function (objArray) { 
    for (var i = 0; i < objArray.length; i++) { 
     this.addChild(objArray[i]); 
    } 
}; 

Node.prototype.addChild = function (obj) { 
    if (obj instanceof Node) { 
     this.Children.push(obj); 
    } else { 
     var n = new Node(obj); 
     this.Children.push(n); 
    } 
}; 

Node.prototype.removeChild = function (n) { 
    var index = this.Children.indexOf(n); 
    if (index > -1) { 
     this.Children.splice(index, 1); 
    } 
}; 

Тогда я могу использовать это как так:

test = new Node({ Id : "Something", Children : [{ Id : "Interior", Children : [] }] }) 

Используя прототип вы уменьшаете объем памяти и не создаю функцию ссылки каждая функция интерьера для каждого Node вы создаете. Каждый Node по-прежнему будет ссылаться на внутренние данные через переменную this.

Смежные вопросы