В чем разница между $root и $parent?

Я изучаю KnockoutJS, но я не понимаю разницы между использованием $root и $parent. См. этот jsfiddle или код ниже:

<div data-bind="foreach:mainloop">
    $data Value: <span data-bind="text:$data.firstName"></span> 
                  <span data-bind="text:$data.lastName"></span> --(1)

    <br/>
    $parent Value: <span data-bind="text:firstName"> </span> 
                   <span data-bind="text:$parent.lastName"></span>
    <br/>
    $root Value: <span data-bind="text:firstName"></span>
                 <span data-bind="text:$root.lastName"></span>
    <br/>
        <hr/>
</div>
var mainLoopModel = function () {
    var self = this; // Root Level scope
    self.mainloop = ko.observableArray([{
        'firstName': 'jhon'
    }, {
        'firstName': 'sam'
    }]);
    self.lastName = ko.observable('peters');
    /*if you remove $data before lastName in note (1) you get undefined error because because mainloop dont have lastName root model has lastName so you have to access using parent or higher level */
}

ko.applyBindings(new mainLoopModel());

В приведенном выше коде $root и $parent оба используются для той же цели: для ссылки на внешнюю переменную области видимости. Я просто хочу знать, есть ли разница между обычаями $root и $parent? Если да, то, пожалуйста, помогите мне разобраться с хорошим примером для правильного использования.

Ответы

Ответ 1

Они похожи, но разные:

  • $root относится к модели представления, примененной к DOM с помощью ko.applyBindings;
  • $parent ссылается на непосредственную внешнюю область;

Или, визуально, с точки зрения $data:

tree visualization

Или словами соответствующей документации:

  • $parent: это объект модели представления в родительском контексте, тот, который находится вне текущего контекста.

  • $root: это объект модели основного представления в корневом контексте, то есть в самом верхнем родительском контексте. Обычно это объект, который был передан ko.applyBindings. Это эквивалентно $parents[$parents.length - 1].

  • $data: это объект модели представления в текущем контексте. В контексте root $ data и $ root эквивалентны.

Вы увидите практическую разницу только в том случае, если у вас есть модели, вложенные более чем в один уровень, иначе они будут равносильны одному и тому же.

Это преимущество довольно просто продемонстрировать:

var Person = function(name) {
  var self = this;
  self.name = ko.observable(name);
  self.children = ko.observableArray([]);
}
  
var ViewModel = function() {
  var self = this;
  self.name = 'root view model';
  self.mainPerson = ko.observable();
}

var vm = new ViewModel(),
    grandpa = new Person('grandpa'),
    daddy = new Person('daddy'),
    son1 = new Person('marc'),
    son2 = new Person('john');

vm.mainPerson(grandpa);
grandpa.children.push(daddy);
daddy.children.push(son1);
daddy.children.push(son2);

ko.applyBindings(vm);
th, td { padding: 10px; border: 1px solid gray; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<script type="text/html" id="person">
  <tr>
    <td data-bind="text: $root.name"></td>
    <td data-bind="text: $parent.name"></td>
    <td data-bind="text: $data.name"></td>
  </tr>
  <!-- ko template: { name: 'person', foreach: children } --><!-- /ko -->
</script>

<table>
  <tr>
    <th>$root</th>
    <th>$parent</th>
    <th>$data</th>
  </tr>
  <!-- ko template: { name: 'person', data: mainPerson } --><!-- /ko -->
</table>