一个可写的计算可观察对象真的需要一个额外的内部可观察对象吗?

Does a writable computed observable really need an extra internal observable?

我正在尝试使用一个可写的计算可观察对象,但我并没有真正理解为什么我不能通过键入它来获取可观察对象中的一些数据。我发现我需要一个额外的 observable 来将内容从 write: 复制到 read:,这看起来很奇怪。

        self.fullName = ko.pureComputed({
            read: function () {
                return ...data from other observables to show in the observable;
            },
            write: function (value) {
                  // value is the content in the input
                  // can be sent to other observables                                       
            },
            owner: self
        });

我发现在上面的模型中,你在observable中输入的内容并不是真的在里面。

在下面的完整示例(包括测试输出和注释)中,我使用一个额外的可观察对象将数据从 write: 复制到 read:。在我的项目中至关重要的是复选框,用于决定是通过输入其中一个来相同地填充两个可观察量,还是通过输入两个来不同地填充两个可观察量。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <title>Writable computed observables</title>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <script src='https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js'></script>
    </head>
    <body>
        <h1>Writable computed observables</h1>
        <p>See: <a href="http://knockoutjs.com/documentation/computed-writable.html">Knockout Doc</a></p>
        <h2>Original example</h2>
        <div>
            First name: <input data-bind="textInput: firstName" />
            <span data-bind="text: firstName"></span>
        </div>
        <div>
            Last name: <input data-bind="textInput: lastName" />
            <span data-bind="text: lastName"></span>
        </div>
        <div class="heading">
            Hello, <input data-bind="textInput: fullName" />
            <span data-bind="text: fullName"></span>
        </div>
        <h2>My example</h2>
        <div>
            Name: <input data-bind="textInput: Name" />
            <span data-bind="text: Name"></span>
        </div>
         <div>
            Mirror first name? <input type="checkbox" data-bind="checked: cbMirror" />
            <span data-bind="text: cbMirror"></span>
        </div>
        <script>
            function MyViewModel() {
                var self = this;
                // example from knockout site:
                self.firstName = ko.observable('Planet');
                self.lastName = ko.observable('Earth');

                self.fullName = ko.pureComputed({
                    read: function () {
                        //return;
                        return self.firstName() + " " + self.lastName();
                    },
                    write: function (value) {
                          // value is the content in the input field, visible on form,
                          // but apparently not yet in the observable.
                          // now copy this value to first/last-name observables,
                          // that in turn copy it to the read-function,
                          // that returns it to the observable.
                        var lastSpacePos = value.lastIndexOf(" ");
                        if (lastSpacePos > 0) { // Ignore values with no space character
                            self.firstName(value.substring(0, lastSpacePos)); // Update "firstName"
                            self.lastName(value.substring(lastSpacePos + 1)); // Update "lastName"
                        }
                    },
                    owner: self
                });

                // checkbox whether or not to mirror between two fields            
                self.cbMirror = ko.observable(false);
                // this observable is to help the writable computed observable to copy input from write() to read()
                self.tmpName = ko.observable();
                // the writable computed observable that may mirror another field, depending on the checkbox
                self.Name = ko.pureComputed({
                        read: function () {
                            return self.cbMirror() ? self.firstName() : self.tmpName();
                        },
                        write: function (value) {
                            //if (self.cbMirror()){
                            //  self.firstName(value);
                            //}else{
                                self.tmpName(value);
                            //}
                        },
                        owner: self
                });
            }

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

因此,问题是:真的没有更好的方法可以直接从 write: 获取一些内容到 read: 而无需额外的可观察 self.tmpName 吗?


更新:

通过从下面的答案中获得的理解,我可以简化示例代码的 write: 部分,请参阅我注释掉的不需要的代码。

是的,如果您想存储用户输入,您需要一个可观察对象。计算不存储信息它只修改它。这就像变量和函数之间的区别。函数不会存储它们的值供以后查看,它只是修改输入并提供输出。

可写计算可观察对象不存储数据。它将数据传递给后备可观察对象。这就是写入部分的全部要点是获取值并将其存储在某个地方。如果您添加另一个跨度来查看 tmpName 的值,您将看到它正在存储您键入的任何内容,除非选中 cbMirror。