2012-06-13 30 views
6

Ho due oggetti JavaScript:valori rimozione di default da un oggetto

var a = { 
    x: 1, 
    y: { 
     faz: 'hello', 
     baz: '' 
    }, 
    z: [1, 2] 
}; 


var defaults = { 
    x: 2, 
    y: { 
     faz: '', 
     baz: '' 
    }, 
    z: [1, 2] 
}; 

voglio tenere solo i campi di a che sono diversi dal default:

a = remove_defaults(a, defaults); // <---- i need this fnc 
{ 
    x: 1, 
    y: { 
     faz: 'hello' 
    } 
} 

L'obiettivo è per rimuovere i valori predefiniti da un oggetto che funge da stato (via URL). Lo stato può avere campi nidificati, quindi un confronto superficiale non è sufficiente. I valori delle foglie sono tutti primitivi (numero, stringa, bool).

(questo è un po 'come il contrario di underscore.js s' _.defaults() metodo)

Qual è il modo migliore per raggiungere questo obiettivo?


La soluzione può utilizzare underscore.js se questo aiuta, ma non jquery.

+1

iterare in modo ricorsivo sulle proprietà e confrontarne i valori. Non esiste un metodo integrato. –

risposta

3

Prova questo:

function removeDuplicates(a, defaults, result) { 
    for (var i in a) { 
    if (i in defaults) { 
     if (typeof a[i] == "object" 
      && typeof defaults[i] == "object" 
      && Object.prototype.toString.call(defaults[i]) !== '[object Array]') { 
     result[i] = removeDuplicates(a[i], defaults[i], {}); 
     } else if (a[i] !== defaults[i]) { 
     result[i] = a[i]; 
     } 
    } else { 
     result[i] = a[i]; 
    } 
    } 

    return result; 
} 


var result = removeDuplicates(a, defaults, {}); 
+1

Cheers! Ma a cosa serve la parte 'a [i] &&'? Questo ignorerà tutto ciò che è falso, come 'false',' 0', '''', 'undefined', che sembra un bug? – user124114

+1

hai ragione, ho corretto il codice. – ioseb

+0

Oh, ho appena realizzato che c'è un grosso bug - tutti i campi copiati vanno nello scope globale di 'result', invece che nei rispettivi sottocampi! – user124114

1
function remove_defaults(obj, defaults) { 
    for (var i in obj) { 
    if (typeof obj[i] == 'object') { 
     obj[i] = remove_defaults(obj[i], defaults[i]); 
     continue; 
    } 
    if (defaults[i] !== undefined && obj[i] == defaults[i]) { 
     delete obj[i]; 
    } 
    } 
    return obj; 
} 

Fiddle: http://jsfiddle.net/ybVGq/

+0

Questo lascia la matrice 'z' nel risultato. Penso che la soluzione di @ ioseb sia migliore, perché elimina anche oggetti nidificati una volta che sono completamente vuoti (= tutti i valori interni erano uguali a quelli di default). – user124114

+0

Sì, l'ho notato. Questo perché stavo usando 'delete' invece di creare un array completamente nuovo. – jeremyharris

0

mio introito:

function no_defaults(obj, defaults) { 
    if ((obj instanceof Array) && (defaults instanceof Array)) { 
     var result = _.difference(obj, defaults); 
     return _.isEmpty(result) ? undefined : result; 
    } 
    if ((obj instanceof Array) || (defaults instanceof Array)) 
     return _.clone(obj); 
    if (typeof obj == "object" && typeof defaults == "object") { 
     var result = {}; 
     for (var prop in obj) { 
      var res = prop in defaults ? no_defaults(obj[prop], defaults[prop]) : _.clone(obj[prop]); 
      if (res !== undefined) 
       result[prop] = res; 
     } 
     return _.isEmpty(result) ? undefined : result; 
    } 
    return _.isEqual(obj, defaults) ? undefined : _.clone(obj); 
} 

Nota questo profondo-processi oggetti, ma non array. Gli array vengono elaborati solo per una differenza minima dei loro elementi diretti - se gli elementi stessi necessitano di no_default, questa funzione non funzionerà. Ma questo va bene per il mio caso d'uso previsto.