15

JQuery + Knockoutを使用するリッチな AJAX ベースの Web アプリケーションがあります。Knockout ビュー モデルをラップして.reset().isDirty( ) などのユーティリティ メソッドを公開する JQuery プラグインがあります。

.setBaseline()というメソッドがあります。このメソッドは、(マッピング プラグインを介して) データ モデルが入力されると、基本的にデータ モデルのスナップショットを取得します。次に、このスナップショットを使用して、モデルが変更されたかどうかをすばやく判断できます。

私が探しているのは、オブジェクトの 1 つがマスターと見なされる2 つの 2 つの JavaScript オブジェクトの違いを表すオブジェクトを返すことができるある種の汎用関数です。

たとえば、これが私のスナップショットであるとします。

var snapShot = {
  name: "Joe",
  address: "123 Main Street",
  age: 30,
  favoriteColorPriority: {
     yellow: 1,
     pink: 2,
     blue: 3
  }
};

次に、ライブ データが次のようになっているとします。

var liveData = {
    name: "Joseph",
    address: "123 Main Street",
    age: 30,
    favoriteColorPriority: {
        yellow: 1,
        pink: 3,
        blue: 2
    }
};

次を返す.getChanges(snapShot, liveData)ユーティリティ関数が必要です。

var differences = {
    name: "Joseph",
    favoriteColorPriority: {
        pink: 3,
        blue: 2
    }
};

_.underscore ライブラリにこのようなものがあるのではないかと期待していましたが、このように機能すると思われるものは見つかりませんでした。

4

7 に答える 7

17

アンダースコアにそのような機能はないと思いますが、自分で実装するのは簡単です:

function getChanges(prev, now) {
    var changes = {};
    for (var prop in now) {
        if (!prev || prev[prop] !== now[prop]) {
            if (typeof now[prop] == "object") {
                var c = getChanges(prev[prop], now[prop]);
                if (! _.isEmpty(c) ) // underscore
                    changes[prop] = c;
            } else {
                changes[prop] = now[prop];
            }
        }
    }
    return changes;
}

また

function getChanges(prev, now) {
    var changes = {}, prop, pc;
    for (prop in now) {
        if (!prev || prev[prop] !== now[prop]) {
            if (typeof now[prop] == "object") {
                if(c = getChanges(prev[prop], now[prop]))
                    changes[prop] = c;
            } else {
                changes[prop] = now[prop];
            }
        }
    }
    for (prop in changes)
        return changes;
    return false; // false when unchanged
}

これは、配列 (またはその他の非プレーン オブジェクト) または異なる構造のオブジェクト (削除、プリミティブからオブジェクト タイプへの変更) では機能しません。

于 2012-06-13T19:52:42.007 に答える
3

私自身の回答を投稿して、配列でも機能する最終的な実装を人々が確認できるようにします。以下のコードでは、"um" が名前空間であり、Underscore.js の _.isArray() および _.isObject メソッドも使用しています。

「_KO」を検索するコードは、オブジェクトに存在する過去の Knockout.js メンバーをスキップするために使用されます。

// This function compares 'now' to 'prev' and returns a new JavaScript object that contains only
// differences between 'now' and 'prev'. If 'prev' contains members that are missing from 'now',
// those members are *not* returned. 'now' is treated as the master list.
um.utils.getChanges = function (prev, now) {
    var changes = {};
    var prop = {};
    var c = {};
    //-----

    for (prop in now) { //ignore jslint
        if (prop.indexOf("_KO") > -1) {
            continue; //ignore jslint
        }

        if (!prev || prev[prop] !== now[prop]) {
            if (_.isArray(now[prop])) {
                changes[prop] = now[prop];
            }
            else if (_.isObject(now[prop])) {
                // Recursion alert
                c = um.utils.getChanges(prev[prop], now[prop]);
                if (!_.isEmpty(c)) {
                    changes[prop] = c;
                }
            } else {
                changes[prop] = now[prop];
            }
        }
    }

    return changes;
};
于 2013-01-22T22:10:37.370 に答える
1

プロジェクトでJsonDiffPatchを使用してデルタを見つけ、それをネット経由で転送し、反対側でオブジェクトにパッチを適用して正確なコピーを取得しています。とても使いやすく、とてもうまく機能します。

また、配列でも機能します。

于 2014-01-18T02:58:48.800 に答える
0

これには jquery を使用する必要はありません。最近、これを行うモジュールを作成しました: https://github.com/Tixit/odiff。次に例を示します。

var a = [{a:1,b:2,c:3},              {x:1,y: 2, z:3},              {w:9,q:8,r:7}]
var b = [{a:1,b:2,c:3},{t:4,y:5,u:6},{x:1,y:'3',z:3},{t:9,y:9,u:9},{w:9,q:8,r:7}]

var diffs = odiff(a,b)

/* diffs now contains:
[{type: 'add', path:[], index: 2, vals: [{t:9,y:9,u:9}]},
 {type: 'set', path:[1,'y'], val: '3'},
 {type: 'add', path:[], index: 1, vals: [{t:4,y:5,u:6}]}
]
*/

odiff の readme では、私のニーズに合わないと判断した他のモジュールをリストアップしました。

于 2015-07-06T20:29:55.633 に答える
0

上記のソリューションに基づいています。このバージョンではバグが修正されており、一部の変更は元のソリューションでは検出されません。

getChanges = function (prev, now) {
        var changes = {}, prop, pc;
        for (prop in now) {
            if (!prev || prev[prop] !== now[prop]) {
                if (typeof now[prop] == "object") {
                    if (c = getChanges(prev[prop], now[prop]))
                        changes[prop] = c;
                } else {
                    changes[prop] = now[prop];
                }
            }
        }

        for (prop in prev) {
            if (!now || now[prop] !== prev[prop]) {
                if (typeof prev[prop] == "object") {
                    if (c = getChanges(now[prop], prev[prop]))
                        changes[prop] = c;
                } else {
                    changes[prop] = prev[prop];
                }
            }
        }

        return changes;
    };
于 2016-03-09T15:26:59.437 に答える