3

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

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

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

   return {
      customProperty: customProperty
   };
} ();

从这里,您可以看到 customProperty 被分配给初始值为 0 的 Knockout 数字 observable。

在包含上述 JavaScript 的 HTML 文档中,我有一个 SPAN 元素,它具有订阅 customProperty observable 的 data-bind 属性,如下所示:

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

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

vm.customProperty(10);

我的问题:

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

  2. 我发现使用括号也可以:

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

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

    var customProperty = ko.numericObservable(0);

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

4

1 回答 1

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

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

  3. customProperty是一个函数,特别是 a ko.observable,这意味着它支持订阅和通知,除了使用()or(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 settergetter的属性,因此语法永远不需要括号。带有 settes 和 getter 的属性可以像任何其他属性一样被读取和写入,但在后台运行 setter 或 getter 中的代码,从而允许订阅和通知发生。

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

注释 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)or ko.isObservable(vm.customProperty() == 10)。在这两种情况下,您都会得到false,因为表达式bool在两种情况下都是 a ,而不是可观察的函数。Ko 没有分解表达式并逐个检查它。这将是在第一个表达式中发现customProperty可观察的并且应该被解包的唯一方法。但是ko不是那样做的。

注 3:表达式,作为计算的 observable,在原始评估中使用 observable 属性并更改其值时会重新评估。请注意,如果在第一次评估中您只访问一个 observable 属性,即使代码包含对其他 observable 的引用,它也只会在访问的 observable 更改其值时重新评估。不会“观察到”其他可观察对象的变化。典型的情况是if依赖于不同的可观察对象,具体取决于执行的分支

于 2015-12-16T09:17:42.217 回答