何时在数据绑定表达式中使用或不使用括号

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

我已经看到其他线程,但我仍然感到困惑,我想我在这里提出了一个不同的案例。

我正在使用显示模式 return 我的 HTML 文档的视图模型对象。因此,我有一个看起来像这样的视图模型对象:

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

   return {
      customProperty: customProperty
   };
} ();

由此,您可以看到 customProperty 被分配给初始值为 0 的 Knockout numeric observable。

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

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

到目前为止,还不错。以上工作正常,这意味着每当我在脚本中更改 customProperty 的值时,SPAN 中的文本会立即更新。例如,我可以成功且轻松地使用此表达式将可观察到的 customProperty 的值从 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 是一个 observable,因此当用户更改 input 中的值时,新值将写回 observable。如果你这样做:

<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 setters and getters 的属性,因此语法永远不需要括号。带有 settes 和 getters 的属性像任何其他 属性 一样被读取和写入,但在幕后 setter 或 getter 中的代码运行,允许订阅和通知发生.

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

注释 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:表达式,作为计算的可观察值,当在原始评估中使用可观察值 属性 时被重新评估并且它发生变化它的价值。请注意,如果在第一次评估中您只访问一个可观察对象 属性,即使代码包含对其他可观察对象的引用,也只会在访问的可观察对象更改其值时重新评估。其他 observables 的变化不会是 "observed"。典型情况是 if 依赖于不同的可观察对象,具体取决于执行的分支