如果你想检测并响应一个对象上的变化,你可以使用可观察的对象。如果您想检测和响应一系列对象的变化,请使用`observableArray`。这在许多场景中非常有用,在这些场景中,您正在显示或编辑多个值,并且需要在添加和删除项目时重复显示和消失UI的各个部分。 示例: ``` var myObservableArray = ko.observableArray(); // Initially an empty array myObservableArray.push('Some value'); // Adds the value and notifies observers ``` ***** 关键点:ObservalArray跟踪数组中的对象,而不是这些对象的状态 简单地将一个对象放入observableArray并不能使该对象的所有属性本身都可见。当然,如果您愿意,您可以使这些属性可见,但这是一个独立的选择。`observableArray`只跟踪它持有的对象,并在添加或删除对象时通知侦听器。 ***** 预填充可观察的数组 如果希望可观察数组不以空开头,而是包含一些初始项,请将这些项作为数组传递给构造函数。例如: ``` // This observable array initially contains three objects var anotherObservableArray = ko.observableArray([ { name: "Bungle", type: "Bear" }, { name: "George", type: "Hippo" }, { name: "Zippy", type: "Unknown" } ]); ``` 从## observableArray读取信息 在幕后,observableArray实际上是一个值为数组的可观察对象(另外,observableArray添加了一些下面描述的附加功能)。因此,您可以通过将ObservalArray作为一个无参数的函数调用来获取底层JavaScript数组,就像其他任何可观察对象一样。然后您可以从底层数组中读取信息。例如: ``` alert('The length of the array is ' + myObservableArray().length); alert('The first element is ' + myObservableArray()[0]); ``` 从技术上讲,您可以使用任何本机JavaScript数组函数来操作底层数组,但通常有更好的替代方法。KO的`observableArray`有自己的等效功能,它们更有用,因为: 它们适用于所有目标浏览器。(例如,本机JavaScript indexOf函数在ie8或更早版本上不起作用,但KO的indexOf可以在任何地方使用。) 对于修改数组内容的函数,如`push`和`splice`,KO的方法会自动触发依赖项跟踪机制,以便将更改通知所有注册的侦听器,并且您的UI会自动更新,这意味着使用KO的方法(即ObservalArray.push)之间存在显著差异(…)和JavaScript本地数组方法(即`observeArray().push(…)`,因为后者不会向数组的订阅者发送其内容已更改的任何通知。 ***** **indexOf** indexOf函数返回与参数相等的第一个数组项的索引。例如,myObservableArray.indexOf('Blah')将返回第一个数组项的从零开始的索引,该索引等于Blah,如果找不到匹配值,则返回值-1。 ***** **slice** slice 函数是原生 JavaScript 切片函数的 observableArray 等价物(即,它返回从给定开始索引到给定结束索引的数组条目)。 调用 myObservableArray.slice(...) 相当于在底层数组上调用相同的方法(即 myObservableArray().slice(...))。 ***** 以下所有这些函数都相当于在底层数组上运行原生 JavaScript 数组函数,然后通知侦听器有关更改: push( value ) — 在数组末尾添加一个新项目。 pop() — 从数组中删除最后一个值并返回它。 unshift( value ) — 在数组的开头插入一个新项目。 shift() — 从数组中删除第一个值并返回它。 reverse() — 反转数组的顺序并返回 observableArray(不是底层数组)。 sort() — 对数组内容进行排序并返回 observableArray。默认排序是按字母顺序排列的,但您可以选择传递一个函数来控制数组的排序方式。请参阅下面排序的示例。 splice() — 从给定索引开始移除并返回给定数量的元素。例如, myObservableArray.splice(1, 3) 从索引位置 1 开始删除三个元素(即第 2、第 3 和第 4 个元素)并将它们作为数组返回。 ***** sorted和### reversed `sorted()` — 返回数组的排序副本。 如果您想保留可观察数组的原始顺序但需要按特定顺序显示它,这比排序更可取。 默认排序是按字母顺序排列的,但您可以选择传递一个函数来控制数组的排序方式。 您的函数应该接受数组中的任意两个对象,如果第一个参数较小,则返回负值,正值表示第二个较小,或者为零以将它们视为相等。 例如,要按姓氏对“person”对象数组进行排序,您可以编写: ``` var mySortedArray = ko.pureComputed(function () { return myObservableArray.sorted(function (left, right) { return left.lastName === right.lastName ? 0 : left.lastName < right.lastName ? -1 : 1; }); }); ``` `reversed() `— 返回数组的反转后的副本。 ***** replace,remove和removeAll observableArray 添加了一些默认在 JavaScript 数组中找不到的更有用的方法: replace( oldItem, newItem ) — 用 newItem 替换与 oldItem 相等的第一个值。 remove( someItem ) — 删除所有等于 someItem 的值并将它们作为数组返回。 remove( function (item) { return item.age < 18; } ) — 删除所有年龄属性小于 18 的值,并将它们作为数组返回。 removeAll( ['Chad', 132, undefined] ) — 删除所有等于 'Chad'、123 或 undefined 的值,并将它们作为数组返回。 removeAll() — 删除所有值并将它们作为数组返回。 ***** 确定属性是否为 observableArray 在某些情况下,以编程方式确定您是否正在处理 observableArray 很有用。 Knockout 提供了一个实用函数 `ko.isObservableArray` 来帮助解决这种情况。 ***** 通常,一个 observableArray 会在它发生更改后立即通知其订阅者。 但是如果 observableArray 被重复更改或触发昂贵的更新,您可能会通过限制或延迟更改通知来获得更好的性能。 这是使用 rateLimit 扩展器完成的,如下所示: ``` // Ensure it notifies about changes no more than once per 50-millisecond period myViewModel.myObservableArray.extend({ rateLimit: 50 }); ``` 跟踪数组更改 尽管您可以像任何其他 observable 一样订阅和访问 observableArray,但 Knockout 还提供了一种超快速方法来找出 observable 数组的变化情况(即,刚刚添加、删除或移动了哪些项目)。 您订阅数组更改如下: ``` obsArray.subscribe(fn, thisArg, "arrayChange"); ``` 订阅变更的主要优点: 在大多数情况下,性能是 O(1),即基本上没有性能影响,因为对于简单的操作,(推送、拼接等)Knockout 提供更改日志而不运行任何差异算法。 如果您在不使用典型的数组变异函数的情况下进行了任意更改,则 Knockout 仅依赖于算法。 更改日志只为您提供实际更改的项目。 以下是如何报告更改的示例: ``` var myArray = ko.observableArray(["Alpha", "Beta", "Gamma"]); myArray.push("Delta"); // Changes: [{ index: 3, status: 'added', value: 'Delta' }] // New value: ["Alpha", "Beta", "Gamma", "Delta"] myArray.pop(); // Changes: [{ index: 3, status: 'deleted', value: 'Delta' }] // New value: ["Alpha", "Beta", "Gamma"] myArray.splice(1, 2, "Omega"); // Changes: // [{ index: 1, status: 'deleted', value: 'Beta' }, // { index: 1, status: 'added', value: 'Omega' }, // { index: 2, status: 'deleted', value: 'Gamma' }] // New value: ["Alpha", "Omega"] myArray.reverse(); // Changes: // [{ index: 0, moved: 1, status: 'deleted', value: 'Alpha' }, // { index: 1, moved: 0, status: 'added', value: 'Alpha' }] // New value: ["Omega", "Alpha"] ``` 如上所示,更改报告为添加和删除值的列表。 删除项的索引引用原始数组,添加项的索引引用新数组。 当项目被重新排序时,如上面的最后一个例子所示,您还将获得移动的信息。 您可以选择忽略移动的信息,并将其解释为删除的原始 Alpha 和添加到数组末尾的不同 Alpha。 或者,您可以认识到移动的信息告诉您,您可以将添加和删除的值视为仅更改位置的同一项目(通过匹配索引)。 observableArray 在构造时启用了数组跟踪,但您可以扩展任何其他订阅(即 ko.observable 和 ko.computed),如下所示: ``` trackable = ko.observable().extend({trackArrayChanges: true}); ```