0

我一直在尝试确定为什么计算值上的写入函数至少不会自动触发突变事件。

我所说的一个例子:

<span data-bind="text: fullName"></span>
<input data-bind="value: fullName"/>

使用以下 JavaScript。

<script type="text/javascript">
function MyViewModel() {
    this.firstName = 'first';
    this.lastName = 'last';

    this.fullName = ko.computed({
        read: function () {
            return this.firstName + " " + this.lastName;
        },
        write: function (value) {
            var lastSpacePos = value.lastIndexOf(" ");
            if (lastSpacePos > 0) { // Ignore values with no space character
                this.firstName = value.substring(0, lastSpacePos); // Update "firstName"
                this.lastName = value.substring(lastSpacePos + 1); // Update "lastName"
            }
        },
        owner: this
    });
}

ko.applyBindings(new MyViewModel());

我理解这种情况的发生,因为 firstName 和 lastName 不是可观察的,但我不明白为什么。即使底层数据在其他地方单独使用,至少任何使用 fullName 的字段都会更新,这似乎是合乎逻辑的。

所以我的问题具体是:

  1. 为什么会这样?
  2. 如果你不想观察名字或姓氏,你怎么能绕过它?

http://jsfiddle.net/TWR6Y/

4

1 回答 1

4

这与依赖跟踪的工作方式有关

  1. 每当你声明一个计算的 observable 时,KO 立即调用它的求值函数来获取它的初始值。
  2. 当您的评估器功能运行时,KO 会记录您的评估器读取其值的任何可观察对象(或计算的可观察对象)。
  3. 当你的评估器完成后,KO 为你接触过的每个可观察对象(或计算的可观察对象)设置订阅。订阅回调设置为使您的评估程序再次运行,将整个过程循环回第 1 步(处理任何不再适用的旧订阅)。
  4. KO 通知任何订阅者你计算的 observable 的新值。

由于firstNameand lastNameare not ko.observable's,KO 不会将它们添加到日志中(参见步骤 2)。因此,您的代码(没有 observables)将不起作用。

进一步总结答案。在这个问题和更新时的 Javascript 无法为原生类型提供事件处理。Knockout 通过处理数据来创建一个可以看到对象突变的截取点来克服这个问题。在不拦截的情况下观察本地人的唯一方法是扫描,这是低效的。

Object.observe将克服这个问题。

于 2013-02-23T19:38:33.430 回答