在数据绑定表达式中,何时使用或不使用带可观察性的括号

When to use or not use parentheses with observables in data-binding expressions

本文关键字:可观察性 表达式 数据绑定 何时使      更新时间:2023-09-26

我已经看到了关于这方面的其他线程,但我仍然感到困惑,我认为我在这里提出了一个不同的情况。

我正在使用揭示模式将视图模型对象返回到我的HTML文档中。因此,我有一个视图模型对象,看起来像这样:

var vm = function() {
   var customProperty = ko.numbericObservable(0);
   return {
      customProperty: customProperty
   };
} ();

从中,您可以看到customProperty正被分配给一个初始值为0的Knockout数值可观察对象。

在包含上述JavaScript的HTML文档中,我有一个SPAN元素,该元素具有订阅customProperty observable的数据绑定属性,如下所示:

<span data-bind="text: customProperty" 
  id="customProperty" style="font-weight:bold"></span>

到目前为止,一切都很好。上面的操作很好,这意味着每当我在脚本中更改customProperty的值时,SPAN中的文本就会立即更新。例如,我可以成功地轻松地使用这个表达式将customProperty observable的值从0更改为10:

vm.customProperty(10);

我的问题:

  1. 请注意,在引用数据绑定属性中的customProperty值时,我没有使用括号。为什么不需要括号?

  2. 我发现使用括号也有效:

我理解为什么使用括号有效(因为我正在阅读可观察到的Knockout的值)。但是为什么不需要括号呢?换句话说,为什么第1点中的数据绑定表达式会起作用?

  1. 最后,这项任务到底发生了什么?

    var customProperty = ko.numericObservable(0);

customProperty最终是否持有指向名为customProperty()的函数的指针?

  1. 当ko解析绑定时,它会检查表达式是否是可观察的,正如您所知,它是一个函数。如果表达式是可观察的,ko会自动打开值以显示它,但它也允许订阅和通知。

  2. 在这种情况下,当ko解析表达式时,它会找到一个值,而不是一个可观察的值,因此,它也可以正确地显示值(值更改>视图更新)。但是,您将丢失从视图到值的绑定(输入值更改>可观察不更新),因为它不是可观察的。有关更多详细信息,请参阅下面的说明和片段。

  3. customProperty是一个函数,特别是ko.observable,这意味着除了使用()(newValue)语法读取或设置值之外,它还支持订阅和通知

注意:使用括号和不使用括号之间的区别是巨大的。如果你这样做:

<input type="text" data-bind="value: customProperty" ...

正如我在1中所解释的,ko发现customProperty是一个可观测值,因此当用户更改input中的值时,新值会写回可观测值。如果你这样做:

<input type="text" data-bind="value: customProperty()" ...

正如我在2中所解释的,ko找到了一个值,而不是一个可观察的值。因此,如果用户通过键入input来更改其值,则新值不会反馈给可观察对象,因为ko不知道它是可观察对象。(但是,如果更新了可观察值,则视图会发生更改,因为依赖关系是在表达式求值期间发现和订阅的)。

var vm = {
	customProperty: ko.observable(10)
};
ko.applyBindings(vm);
body {
  font-family: Segoe, Arial
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
data-bind="value: customProperty()"<br/>
<input type="text" data-bind="value: customProperty(), valueUpdate: 'keyup'"/><br/>
If you change the input text, customProperty is not updated
<br/><br/>
data-bind="value: customProperty"<br/>
<input type="text" data-bind="value: customProperty, valueUpdate: 'keyup'"/><br/>
If you change the input text, customProperty changes
<br/><br/>
customProperty value: <span data-bind="text: customProperty"/>

在其他框架中,如Angular,它不使用函数,而是使用带有JavaScript setter和getter的属性,这样语法就不需要括号了。具有setter和getter的属性可以像其他任何属性一样进行读取和写入,但在幕后,setter或getter中的代码会运行,从而允许进行订阅和通知。

注2(因为评论中有问题)。你可以这样想:当ko解析绑定表达式时,它会立即评估整个表达式,并检查结果是否是可观察的。所以,当你有一个这样的表达式:customProperty == 10时,当ko对它进行求值时,它发现它不是一个可观察的(而是一个布尔值),并且不需要额外的步骤来获得值。结果将始终为false,因为customPropertyfunction,因此为'!=10’。如果将表达式更改为以下表达式:customProperty() == 10,则自定义特性值将被()展开,并且比较将按预期进行。顺便说一句,尽量不要在绑定表达式中包含代码:在模型中使用计算的可观察性(如果可能的话,最好是纯计算的)要好得多

注释2的控制台实验

键入:var vm = {customProperty: ko.observable(10)}以创建视图模型。

键入:vm.customProperty(),您将看到10

键入:vm.customProperty,您将看到function ...

键入:vm.customProperty() == 10,您将看到true(难怪,10 == 10

键入:vm.customProperty == 10,您将获得false(因为function != 10

此外,键入ko.isObservable(vm.customProperty),您将看到true。ko就是这么做的。所以ko知道它必须打开价值。键入ko.unwrap(vm.customProperty),您将看到10

最后,键入ko.isObservable(vm.customProperty == 10)ko.isObservable(vm.customProperty() == 10)。在这两种情况下,您都会得到false,因为在这两个情况下,表达式都是bool,而不是可观察的函数。Ko不会对表达式进行反编译并逐个检查。这将是在第一个表达式中发现customProperty是可观察的并且应该被展开的唯一方法。但是ko并不是那样做的。

注3:当在原始评估中使用可观测属性且其值发生变化时,表达式作为计算的可观测值将重新评估。请注意,如果在第一次评估中只访问一个可观察属性,即使代码中包含对其他可观察属性的引用,也只有当访问的可观察属性更改其值时,才会对其进行重新评估。其他可观察性的变化不会被"观察到"。典型的情况是if,它取决于不同的可观测值,这些可观测值取决于执行的分支