2010-08-04 11 views
7

Je cherche à réduire les exigences de stockage pour les données JSON en les déliant par rapport à un ensemble de valeurs par défaut. Au fond, ce que je veux est l'inverse de la fonction de jQuery .extend(), de sorte que le test suivant passe pour les objets compatibles JSON arbitraires:Inverse de jQuery.extend (true, ...)

function test_delta(defaults, delta) { 
    var current = $.extend(true, {}, defaults, delta); 

    QUnit.same(get_delta(current, defaults), delta); 
} 

Avant de commencer à écrire mon propre get_delta(), est une personne au courant d'une implémentation existante?

+0

Vous devrez vous-même gérer celui-ci, le chemin dur (en boucle imbriquée). Comme tu le sais probablement. C'est encore plus amusant si vos données JSON ont une profondeur arbitraire. –

+0

Ouais, j'ai déjà trouvé des cas intéressants; C'est pourquoi j'ai pensé que je demanderais le "SO oracle" avant de creuser moi-même. Et bien. :-) –

+0

Un bon point de départ serait de regarder la fonction jQuery.fn.extend dans [source jQuery] (http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js). – calvinf

Répondre

1

Ce que vous cherchez vraiment, c'est un algorithme diff (erential).

Pas trop difficile d'écrire -



function diff (obj1, obj2) { 
    var delta = {}; 

    for (var x in obj1) { 
     if (obj2.hasOwnProperty(x)) { 
      if (typeof obj2[x] == "object") { 
       //recurse nested objects/arrays 
       delta[x] = diff(obj1[x], obj2[x]); 
      } 
      else { 
       //if obj2 doesn't match then - modified attribute 
       if (obj2[x] != obj1[x]) { 
        delta[x] = obj1[x]; 
       } 
      }   
     } 
     else { 
      //obj2 doesn't have this - new attribute 
      delta[x] = obj1[x]; 
     } 
    } 

    return delta; 
} 

alert( 
    JSON.stringify(
    diff({ hello : 'world', gone : 'fishing' }, 
      { hello : 'world' }) 
) 
); 

//outputs: 
{ gone : 'fishing' } 

Comme vous pouvez le voir c'est une implémentation très simple - vous pouvez l'étendre à fournir un différentiel complet par des ajouts de revenir à obj2 dans un objet séparé.

Ce code n'est pas sans bug, les prototypes d'objets et les fonctions seront traités différemment dans les différents navigateurs, mais cela devrait suffire comme démonstration pour les structures de données.

+0

J'ai essayé de mettre en œuvre le mien, mais il y avait assez de cas de bord peu clairs (en particulier avec les tableaux et les propriétés supprimées) que nous avons décidé d'agrandir simplement la colonne de base de données à la place. –

1

Essayez quelque chose comme ça:

jQuery.extend({ 
    deltaExtend: function(deep, target, defaults, delta){ 
     var result = jQuery.extend.apply(jQuery, arguments); 
     jQuery(result).data('delta', delta); 
     jQuery(result).data('defaults', defaults); 
     return result; 
    } 
}); 

utilisation:

var result = $.deltaExtend(true, {}, defaults, delta); 
$(result).data('delta') //returns delta object 
$(result).data('defaults') //returns default object 

Il peut également être modifié pour le faire fonctionner pour les objets N, juste besoin d'un peu plus de réflexion.

+0

C'est une idée très intéressante! Malheureusement, '$ .extend' n'est pas utilisé pour créer l'objet" result ", dans mon cas. C'était pour un système de portail, où chaque portlet pouvait définir ses propres paramètres par défaut. Les paramètres "en cours" seraient alors modifiés librement sur la durée de vie de la page et, quand viendrait le temps de sauvegarder l'état du portlet sur le serveur, j'espérais effectuer un delta "aveugle" pour réduire les besoins de stockage. –

+0

J'ai une autre solution à l'esprit, quels navigateurs soutenez-vous, et quelles versions, plus spécifiquement vous soutenez IE

1

Je sais que c'est un peu tard pour être pertinent pour le démarreur de sujet, mais vous voudrez peut-être jeter un oeil à la fonction _.omit(object, *keys) de Underscore.js. C'est juste cela.

+0

Mais comment connaissez-vous les «clés»? – Bergi

+0

Les clés proviennent de l'objet où les valeurs par défaut sont stockées. '_.keys (defaultObject)' vous donne un tableau de ses clés. – oley

+0

Vous auriez dû le mentionner dans votre réponse ... Et notez que cette méthode ne fonctionne que pour les propriétés * ajoutées *, pas pour toutes celles * modifiées *. – Bergi