Knockoutクイックハンド-4:トップクラスの特性を知る必要があります

16700 ワード

Knockoutの最高の特徴は、その拡張性です.Knockoutには多くの拡張点があり、私たちのアプリケーションを作成するための多くのツールが含まれています.多くの開発者は、Knockoutコアライブラリ以外のスクリプトライブラリ(jQueryも含む)を使用せずに素晴らしいサイトを作成しています.
Subscribables
在庫管理プログラムを作成すると、KnockoutでObservableがコアオブジェクトであることがわかりやすくなります.Observable、ObservableArrayおよびComputed Observablesの最下位はSubscribable、Subscribableは3つのメソッドと1つのSubscriptions配列を含むオブジェクトです.
  • subscribe:このメソッドは、サブスクリプションをトピックオブジェクトに追加し、サブスクリプションのトピックがアラートを発行すると、サブスクリプションが呼び出され、デフォルトのアラートタイプはchangeです.
  • notifySubscribers:このメソッドはすべてのサブスクリプションを呼び出し、サブスクリプションのコールバックメソッドにパラメータを渡します.
  • extend:このメソッドは、トピックオブジェクトに拡張
  • を追加します.
    次のコードは、前の2つの方法の使用を示し、パブリケーションとサブスクリプションを実現します.
    var test = ko.observable();
    
    // create a subscription for the "test-event"
    
    test.subscribe(function (val) {
    
        console.log(val);
    
    }, test, "test-event");
    
    test.notifySubscribers("Hello World", "test-event");

    Knockoutで購読するクールな特性の一つは、Javascriptオブジェクトに任意にブレンドできることであり、次のコードは通常のコードで使用する方法を示しています.
    // Dummy Subscribable
    function PubSub() {
        // inherit Subscribable
        ko.subscribable.call(this);
    }
    
    // create an instance of our Subscribable
    var pubsub = new PubSub();
    // make a subscription
    var subscription = pubsub.subscribe(function (val) {
        console.log(val);
    }, pubsub, 'test-topic');
    
    pubsub.notifySubscribers("hello world", "test-topic");
    // console: "hello world"
    // clean up things
    subscription.dispose();

    サブスクリプション可能オブジェクトのsubscribeメソッドを呼び出した後、開発者は通常、このsubscribeメソッドが返すサブスクリプションオブジェクトを無視することができるSubscriptionオブジェクトを得たが、このサブスクリプションオブジェクトSubscriptionによって、サブスクリプションのコールバックメソッドとアプリケーションのコールバックに対する参照を解放することができることに注意しなければならない.disposeメソッドを直接呼び出すと、プログラムがメモリの漏洩を起こさないことを確認できます.
    今では、Knockoutのコア処理メカニズム、Subscribableを理解しています.私たちはKnockoutが他のモードでどのようにその使い方を拡張するかを学びます.
    Observables
    KnockoutのObservableオブジェクトは、サブスクリプションメカニズムを実現するトップオブジェクトであり、Knockoutライブラリの中で最も簡単で、最も強力な部分でもあります.次のコードはObservableを実現するための基本思想を示している.
    // Very Simple Knockout Observable Implementation
    // ko.observable is actually a function factory
    
    ko.observable = function (initialValue) {
    
        // private variable to hold the Observable's value
        var _latestValue = initialValue;
    
        // the actual "Observable" function
        function observable() {
            // one or more args, so it's a Write
            if (arguments.length > 0) {
                // set the private variable
                _latestValue = arguments[0];
                // tell any subscribers that things have changed
                observable["notifySubscribers"](_latestValue);
                return this; // Permits chained assignments
            }
    
            else { // no args, so it's a Read
                // just hand back the private variable's value
                return _latestValue;
            }
        }
    
        // inherit from Subscribable
        ko.subscribable.call(observable);
    
        // return the freshly created Observable function
        return observable;
    };

    これはKnockoutにおけるobservableの単純な実装(真の実装コードには大量の強壮性処理コード,検証,依存検出などが含まれている)であり,この実装から実際にobservableは関数のファクトリであり,このファクトリメソッドを呼び出すと新しい関数が生成されることがわかる.ここでは簡単なset/get APIを実現した.パラメータを指定せずに返される関数を呼び出すと、_が返されます.initialValueは、呼び出すときにパラメータを指定すると、_を設定します.initialValueは、すべての購読を通知します.
    イベントドライバのプログラムを作成すると、Observableは多くのアプリケーションを得ることができます.イベントドライバのプログラムアーキテクチャを作成し、プロセス化の方法ではなく、イベント(ボタンのクリックや入力要素の変化など)に依存することができます.
    Observable Array
    観測可能な配列については前述したが,向上はこの特性を深く議論する.前述の例では、Observableは比較的簡単であり、観察可能な配列も同様に簡単であることが示されている.次のコードは、実装のメカニズムを示しています.
    // Very Simple Knockout Observable Array Implementation
    // function factory for observable arrays
    ko.observableArray = function (initialValues) {
    
        // make sure we have an array
        initialValues = initialValues || [];
    
        // create a Knockout Observable around our Array
        var result = ko.observable(initialValues);
    
        // add our Observable Array member functions
        // like "push", "pop", and so forth
        ko.utils.extend(result, ko.observableArray['fn']);
    
        // hand back the Observable we've created
        return result;
    
    };

    ご覧のように、実際には観察可能なオブジェクトであり、この観察可能なオブジェクトの値が配列である以外は.また,マッチング配列ローカルメソッドの拡張メソッドも追加した.Knockoutの著者らは,開発者が通常の配列のように観察可能な配列を使用できるように,これらの作業を完了した.
    観察可能配列の拡張点の1つはそのfn属性であり、自分の関数をこの属性に追加することができ、アプリケーション内のすべての観察可能配列にこの方法を提供することができ、次のコードは、配列内の要素をフィルタするためにフィルタリング方法を追加する方法を示しています.
    ko.observableArray.fn['filter'] = function (filterFunc) {
    
        // get the array
        var underlyingArray = this();
        var result = [];
    
        for (var i = 0; i < underlyingArray.length; i++) {
            var value = underlyingArray[i];
    
            // execute filter logic
            if (filterFunc(value)) {
                result.push(value);
            }
        }
        return result;
    };
    var list = ko.observableArray([1, 2, 3]);
    
    // filter down the list to only odd numbers
    var odds = list.filter(function (item) {
        return (item % 2 === 1);
    });
    
    console.log(odds); // [1, 3]

     
    fn関数の使用は、jQueryスクリプトライブラリを含む多くのスクリプトライブラリで一般的なモードであり、Knockoutも例外ではありません.fnはObservableにも存在するので、同じように拡張することもできます.
    Computed Observable
    計算された観察可能オブジェクトはKnockoutの中で最も強力な特性と言える.他の技術ではなくObservableとObservable Arrayを使用してビューモデルを作成することを学んだ後、大きな進歩がありましたが、さらに素晴らしいことに、他のObservableとObservalbe Arrayに依存する属性を作成することができ、下位属性が変化すると計算結果が同時に変化します.
    計算された観察可能オブジェクトは、通常の観察可能オブジェクトと同様であり、自分の値を保存していない以外は、依存する下位オブジェクトが変化したときにのみ戻り値を再計算する方法を提供し、以下のコードは実装のメカニズムを示す.
    var a = ko.observable(1);
    
    var b = ko.observable(2);
    var sum = ko.computed(function () {
        var total = a() + b();
        // let's log every time this runs
        console.log(total);
        return total;
    });
    
    // console: 3
    a(2); // console: 4
    b(3); // console: 5
    b(3); // (nothing logged)

     
    計算された観察可能なオブジェクトは非常に面白く、巧みに実現されています.自分で掘り起こすことができます.初回のほかに、注意しなければならないポイントがあります.
    まず、計算されたオブジェクトに依存リスト(またはサブスクリプション)が作成され、計算関数が実行されるときにオブジェクトに依存したい場合は、計算関数でこのObservableを呼び出すことを保証する必要があります.次のコードでは、計算オブジェクトの依存オブジェクトを設定し、動的に変更する方法を示します.
    var dep1 = ko.observable(1);
    var dep2 = ko.observable(2);
    var skipDep1 = false;
    var comp = ko.computed(function () {
    
        dep2(); // register dep2 as dependency
        if (!skipDep1) {
            dep1(); // register dep1 as dependency
        }
        console.log('evaluated');
    });
    
    // console: evaluated
    dep1(99); // console: evaluated
    skipDep1 = true;
    dep2(98); // console: evaluated
    dep1(97); // (nothing logged)

     
    一般的に、上記のコードはあまり注意されていません.これにより、コードのデバッグが難しくなり、他の開発者が発生した状況を直感的に認識することが難しくなります.逆に,提案された処理方式は,まず依存オブジェクトからすべての値を取得し,次にプライベート変数を用いて処理論理問題を評価することである.
    2つ目は、すべてのオブジェクトを使用することです.サブスクリプションのコールバック関数は、プロパティの値が変化した場合にのみ、各オブジェクトにequalityComparerというプロパティがあり、プロパティの前後の値が異なるかどうかを検出します.前の例に注意すると、最後の呼び出しは何もしていません.これは、2回目の設定値が3なので.デフォルトのequalityComparerインプリメンテーションはjavascriptのベース値のみを比較し、計算可能なオブジェクトが複雑または複雑でないすべてのオブジェクトに依存する場合、この関数は複数回実行され、次のコードはこの重要な概念を示しています.
    var depPrimitive = ko.observable(1);
    var depObj = ko.observable({ val: 1 });
    var comp = ko.computed(function () {
    
        // register dependencies
        var prim = depPrimitive();
        var obj = depObj();
        console.log("evaluated");
    });
    
    // console: evaluated
    depPrimitive(1); // (nothing logged)
    
    var previous = depObj();
    depObj(previous); // console: evaluated

    重要なのは、この点を理解することです.多くのKnockoutの初心者が複雑な計算可能なオブジェクトを作成し、アプリケーションのパフォーマンスが低下しています.
    最後に、計算された観察可能オブジェクトも独自のset/getを持つことができます.これは、ビューモデルにプライベートな観察可能オブジェクトを持つことができ、共通のset/getを通じて通常の観察可能オブジェクトと同様に使用することができるため、次の世代コードでこの技術を実証します.
    var _val = ko.observable(1);
    
    var vm = {
        val: ko.computed({
    
            read: function () {
                return _val();
            },
    
            write: function (newVal) {
                _val(newVal);
            }
        })
    };
    
    vm.val(2);
    console.log(_val()); // console: 2
    _val(3);
    console.log(vm.val()); // console: 3