2010-08-04 19 views
7

Estoy buscando reducir los requisitos de almacenamiento para los datos JSON al desvirtuarlos contra un conjunto conocido de valores predeterminados. Básicamente, lo que quiero es una inversa de la función de jQuery .extend(), de manera que la siguiente prueba pasa de objetos compatible con JSON arbitrarias:Inverso de jQuery.extend (true, ...)

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

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

Antes de empezar a escribir mi propia get_delta(), es cualquier persona consciente de una implementación existente?

+0

Tendrá que manejar este usted mismo, el camino duro (lazo anidado). Como probablemente sabes. Es incluso más divertido si tus datos JSON tienen una profundidad arbitraria. –

+0

Sí, ya he descubierto algunos casos extremos interesantes; es por eso que pensé que pediría el "SO Oracle" antes de investigarlo yo mismo. Ah bueno. :-) –

+0

Un buen lugar para comenzar sería buscar la función jQuery.fn.extend en [jQuery source] (http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js). – calvinf

Respuesta

1

Lo que realmente está buscando es un algoritmo de diferencia de objetos (erential).

No es demasiado difícil de escribir -



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' } 

Como se puede ver, esta es una aplicación muy básica - se puede extender este para proporcionar un diferencial completa mediante la devolución de adiciones a obj2 en un objeto separado.

Este código no está exento de errores, los objetos y las funciones de los objetos se manejarán de manera diferente en diferentes navegadores, pero debería ser suficiente como una demostración para las estructuras de datos.

+0

Me tomó una puñalada en la implementación de la mía, pero había suficientes casos de bordes poco claros (particularmente con matrices y propiedades eliminadas) que decidimos simplemente ampliar la columna de la base de datos en su lugar. –

1

intentar algo así como que:

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; 
    } 
}); 

uso:

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

También puede ser ajustado para que funcione de N objetos, sólo requiere un poco más de pensamiento.

+0

¡Esta es una idea muy interesante! Desafortunadamente, '$ .extend' no se usa para crear el objeto" resultado ", en mi caso. Esto fue para un sistema de portal, donde cada portlet podría definir su propia configuración predeterminada. La configuración "actual" se modificaría libremente durante la vida útil de la página y, cuando llegara el momento de guardar el estado del portlet en el servidor, esperaba realizar un delta "a ciegas" para reducir los requisitos de almacenamiento. –

+0

Tengo otra solución en mente, ¿a qué navegadores está apoyando y qué versiones, más específicamente, está soportando IE

1

Sé que esto es un poco tarde para ser relevante para el tema de inicio, pero es posible que desee echar un vistazo a la función _.omit(object, *keys) de Underscore.js. Hace exactamente eso.

+0

Pero, ¿cómo sabes las 'claves'? – Bergi

+0

Las claves provienen del objeto donde se almacenan los valores predeterminados. '_.keys (defaultObject)' te da una matriz de sus claves. – oley

+0

Debería haber mencionado eso en su respuesta ... Y tenga en cuenta que este método solo funciona para las propiedades * added *, no para todas las * changed * ones. – Bergi