NgForOf 指令中 ngForTrackBy 的用途是什么

What is the purpose of ngForTrackBy in the NgForOf directive

来自 Angular 的 source code,以下片段让我感到困惑。

 /**
   * A function that defines how to track changes for items in the iterable.
   *
   * When items are added, moved, or removed in the iterable,
   * the directive must re-render the appropriate DOM nodes.
   * To minimize churn in the DOM, only nodes that have changed
   * are re-rendered.
   *
   * By default, the change detector assumes that
   * the object instance identifies the node in the iterable.
   * When this function is supplied, the directive uses
   * the result of calling this function to identify the item node,
   * rather than the identity of the object itself.
   *
   * The function receives two inputs,
   * the iteration index and the node object ID.
   */
  @Input()
  set ngForTrackBy(fn: TrackByFunction<T>) {
    ...
      }
    }
    this._trackByFn = fn;
  }

here 在官方文档中传递 trackBy 函数的示例中。

trackById(index: number, hero: Hero): number { return hero.id; }

源码说明

When this function is supplied, the directive uses the result of calling this function to identify the item node, rather than the identity of the object itself.

但在上面的示例中,我们无论如何都传递了对象本身的标识 (return hero.id;),但是通过一个附加函数。为什么我们需要那个?如果我们没有传递任何此类函数,那么 Angular 不会按照文档默认执行它所做的事情,即获取对象本身的标识吗?

跟踪器函数的显式传递与 Angular 没有它时通常所做的究竟有何不同?

谢谢。

我完全可以看出它的措辞是多么令人困惑。但是当它说“而不是对象本身的身份”时<<它意味着整个对象。在该示例中,默认情况下将跟踪整个英雄对象。通过为其提供跟踪功能,您可以将其缩小到对象的一个​​ 属性(例如 id 属性),而不是跟踪整个对象。从该片段中可能不清楚的是,英雄 class 是否有一些 属性 命名 ID。

Angular 将检查内存中的引用是否为非原始类型。如果你不传递 trackById 方法,每次数组改变时它认为每个对象都是新的并重新创建所有 DOM 节点。

如果传trackById,它会检查原来的对象和新的对象,如果它们的id属性相同,就说它们是同一个对象,不会重新绘制 DOM 节点。

这是一个您也可以 运行 的示例,它很简单 javascript

let obj1 = {id: 1, name: 'test'};
let obj1a = {id: 1, name: 'test'};
let prim1 = 1;
let prim2 = 1;

const checkById = (a, b) => {
  return a.id === b.id;
}

// obj1 and 1a are not the same, because they are different references in memory
console.log("obj1 === obj1a", obj1 === obj1a);

// ob1 and obj1a are the "same" to us though, because the ID property is the same
console.log("checkById(obj1, obj1a)", checkById(obj1, obj1a));

// primitives would be equal
console.log("prim1 === prim2", prim1 === prim2);