KnockoutJS - Computed 可观察对象

Computed 可观察对象是一个依赖于一个或多个可观察对象的函数,并且每当其底层可观察对象(依赖项)发生变化时都会自动更新。

Computed 可观察对象可以链接在一起。

语法

this.varName = ko.computed(function(){
   ...
   ... //  function code
   ...
},this);

示例

让我们看看下面的示例,它演示了计算可观察变量的使用。

<!DOCTYPE html>
   <head >
      <title>KnockoutJS Computed Observables</title>
      <script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js"></script>
   </head>

   <body>
      <p>Enter first number: <input data-bind = "value: a" /></p>
      <p>Enter second number: <input data-bind = "value: b"/></p>
      <p>Average := <span data-bind="text: totalAvg"></span></p>

      <script>
         function MyViewModel() {
            this.a = ko.observable(10);
            this.b = ko.observable(40);

            this.totalAvg = ko.computed(function() {

               if(typeof(this.a()) !== "number" || typeof(this.b()) !== "number") {
                  this.a(Number(this.a()));   //convert string to Number
                  this.b(Number(this.b()));   //convert string to Number
               }

               total = (this.a() + this.b())/2 ;
               return total;
            },this);
         }

         ko.applyBindings(new MyViewModel());
      </script>

   </body>
</html>

以下行中,前两行用于接受输入值。第三行打印这两个数字的平均值。

<p>Enter first number: <input data-bind = "value: a" /></p>
<p>Enter second number: <input data-bind = "value: b"/></p>
<p>Average := <span data-bind = "text: totalAvg"></span></p>

在以下几行中,Observables ab 在 ViewModel 中首次初始化时的类型为数字。然而,在 KO 中,从 UI 接受的每个输入默认都是字符串格式。因此,需要将它们转换为数字,以便对它们执行算术运算。

this.totalAvg = ko.computed(function() {
   
   if(typeof(this.a()) !== "number" || typeof(this.b()) !== "number") {
      this.a(Number(this.a()));   //convert string to Number
      this.b(Number(this.b()));   //convert string to Number
   }
   
   total = (this.a() + this.b())/2 ;
   return total;
},this);

在下面一行中,计算出的平均值显示在 UI 中。请注意,totalAvg 的数据绑定类型只是文本。

<p>Average := <span data-bind = "text: totalAvg"></span></p>

输出

让我们执行以下步骤来查看上述代码的工作原理 −

  • 将上述代码保存在 computed-observable.htm 文件中。

  • 在浏览器中打开此 HTML 文件。

  • 在文本框中输入任意 2 个数字,并观察平均值的计算情况。

管理"This"

请注意,在上面的示例中,第二个参数作为 this 提供给 Computed 函数。如果不提供 this,就无法引用 Observables a()b()

为了解决这个问题,使用 self 变量来保存 this 的引用。这样做,就不需要在整个代码中跟踪 this。相反,可以使用 self

以下 ViewModel 代码是使用 self 为上述示例重写的。

function MyViewModel(){
   self = this;
   self.a = ko.observable(10);
   self.b = ko.observable(40);

   this.totalAvg = ko.computed(function() {
      
      if(typeof(self.a()) !== "number" || typeof(self.b()) !== "number") {
         self.a(Number(self.a()));   //convert string to Number
         self.b(Number(self.b()));   //convert string to Number
      }
      
      total = (self.a() + self.b())/2 ;
      return total;
   });
}

纯计算可观察对象

如果计算可观察对象只是计算并返回值,而不是直接修改其他对象或状态,则应将其声明为计算可观察对象。纯计算可观察对象可帮助 Knockout 高效管理重新评估和内存使用情况。

明确通知订阅者

当计算可观察对象返回原始数据类型值(字符串、布尔值、Null 和数字)时,只有当实际值发生变化时,才会通知其订阅者。这意味着如果 Observable 收到的值与之前的值相同,则不会通知其订阅者。

您可以让 Computed Observable 始终明确通知观察者,即使新值与旧值相同,也可以使用以下 notify 语法。

myViewModel.property = ko.pureComputed(function() {
    return ...; // code logic goes here
}).extend({ notify: 'always' });

限制更改通知

过多昂贵的更新可能会导致性能问题。您可以使用 rateLimit 属性限制从 Observable 接收的通知数量,如下所示。

// 确保每 100 毫秒周期内更新不超过一次
myViewModel.property.extend({ rateLimit: 100 });

确定属性是否为计算可观察对象

在某些情况下,可能需要确定属性是否为计算可观察对象。以下函数可用于识别可观察对象的类型。

Sr.No. 函数
1

ko.isComputed

如果属性为 Computed Observable,则返回 true

2

ko.isObservable

如果属性为 Observable、Observable 数组或 Computed Observable,则返回 true

3

ko.isWritableObservable

如果为 Observable、Observable 数组或 Writable,则返回 true计算可观察对象。(这也称为 ko.isWriteableObservable)

可写的计算可观察对象

计算可观察对象派生自一个或多个其他可观察对象,因此它是只读的。但是,可以使计算可观察对象可写。为此,您需要提供对写入值起作用的回调函数。

这些可写的计算可观察对象的工作方式与常规可观察对象一样。此外,它们需要构建自定义逻辑来干扰读写操作。

可以使用以下链接语法为许多 Observable 或 Computed Observable 属性赋值。

myViewModel.fullName('Tom Smith').age(45)

示例

以下示例演示了 Writable Computable Observable 的使用。

<!DOCTYPE html>
   <head >
      <title>KnockoutJS Writable Computed Observable</title>
      <script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"></script>
   </head>

   <body>
      <p>Enter your birth Date: <input type = "date" data-bind = "value: rawDate" ></p>
      <p><span data-bind = "text: yourAge"></span></p>

      <script>
         function MyViewModel() {
            this.yourAge = ko.observable();
            today = new Date();
            rawDate = ko.observable();

            this.rawDate = ko.pureComputed ({

               read: function() {
                  return this.yourAge;
               },

               write: function(value) {
                  var b = Date.parse(value);    // convert birth date into milliseconds
                  var t = Date.parse(today);    // convert todays date into milliseconds
                  diff = t - b;                 // take difference
                  var y = Math.floor(diff/31449600000);     // difference is converted
                                                            // into years. 31449600000
                                                            //milliseconds form a year.

                  var m = Math.floor((diff % 31449600000)/604800000/4.3);  // calculating
                                                                           // months.
                                                                           // 604800000
                                                                           // milliseconds
                                                                           // form a week.

                  this.yourAge("You are " + y + " year(s) " + m +" months old.");
               },
               owner: this
            });
         }

         ko.applyBindings(new MyViewModel());
      </script>

   </body>
</html>

在上面的代码中,rawDate 是从 UI 接受的 pureComputed 属性。yourAge Observable 派生自 rawDate

JavaScript 中的日期以毫秒为单位进行操作。因此,两个日期(今天日期和出生日期)都转换为毫秒,然后将它们之间的差值转换回年和月。

输出

让我们执行以下步骤来查看上述代码的工作原理 −

  • 将上述代码保存在 writable_computed_observable.htm 文件中。

  • 在浏览器中打开此 HTML 文件。

  • 输入任何出生日期并观察年龄是否已计算。