2013-02-10 13 views
5

Questo codice dimostra al meglio la mia confusione.Perché il metodo .data di jQuery si comporta in questo modo? (Possibile errore?)

var nativeObj, jWrapped, jSelector; 

//WIAT = "What I Am Thinking" 
nativeObj = $('#tableTab') [0]; //WIAT: unwrap the jQuery object created by the selector and get the native DOM object 
jWrapped = $(nativeObj); //WIAT: wrap up the native DOM object again... should be equal to $('#tableTab') 
jSelector = $('#tableTab'); //WIAT: pass the jQuery object as reference to jSelector variable 

// set the data with jQuery's .data method 
$.data(jWrapped, 'key', { test: 12 }); //WIAT: will be equivalant to using $('#tableTab') and should attach the data to it 
$.data($('#tableTab') [0], 'key', { test: 34 }); //WIAT: using the native DOM obj, it shouldn't work with this, since it doesn't specify in the docs 
$.data($('#tableTab') , 'key', { test: 56 }); //WIAT: should rewrite the data in the element to { key: { test: 56} } 

console.log($.data (jWrapped)); // {key:{test:12}} 
console.log($.data (jWrapped[0])); // {key:{test:34}} 
console.log($.data (nativeObj)); // {key:{test:34}} 
console.log($.data ($(nativeObj), 'test')); // undefined 
console.log($.data ($('#tableTab') [0])); // {key:{test:34}} 
console.log($.data ($('#tableTab') , 'test')); // undefined 

Whoa, aspetta, cosa sta succedendo?

1. Perché sto ottenendo risultati diversi? Ho usato solo un selettore e sto facendo riferimento a un elemento.

2. Perché l'oggetto non è il jWrapped e l'oggetto da $('#tableTab') produce lo stesso risultato?

3. Inoltre jWrapped e jWrapped[0] stanno producendo risultati diversi? Il primo è un oggetto jQuery wrapped e il secondo un oggetto DOM nativo. Essenzialmente sono facendo riferimento allo stesso elemento con un risultato diverso! ??

//Now let's see what's inside the objects 
console.log($('#tableTab') [0]); // [object HTMLDivElement]   
console.log(nativeObj); // [object HTMLDivElement] 
console.log($(nativeObj)); // {0:({}), context:({}), length:1} 
console.log(jWrapped); // {0:({}), context:({}), length:1, jQuery182021025872972076787:{toJSON:(function() {}), data:{key:{test:12}}}} 
console.log($('#tableTab')); // {length:1, 0:({}), context:({}), selector:"#tableTab"} 
console.log(jSelector); // {length:1, 0:({}), context:({}), selector:"#tableTab"} 

buona nativeObj == $('#tableTab') [0] questo è quello che mi aspettavo

Whoa, che era strano, perché non fa jWrapped == $(nativeObj)?

Buono, jSelector = $('#tableTab') questo è anche quello che mi aspettavo

Detto questo i dati, vorrei estrapolare che $ .data deve accettare un elemento DOM nativo, tuttavia

$('#tableTab').data('key' , { test: 78 }); 
console.log($('#tableTab').data('key')); // 78 

Umm mi scusi monsieur console ... non un uomo figo.

Ok io sono regalmente confusi e frustrati e odio jQuery e odio Javascript e odio IE ... OK No, ho solo odio IE, ma questa è un'altra storia. Perché jQuery si comporta in modo così strano? Appeso troppo spesso a IE ...

La mia ipotesi è che abbia a che fare con il modo in cui $ .data funziona in jQuery e che in realtà non collega i dati agli elementi, ma piuttosto memorizza i dati in il proprio oggetto e fa riferimento ai dati in base all'analisi dei dati trasmessi che vengono passati. Ho trovato un bug?

Help.

Inoltre ho dato un'occhiata a How does jQuery .data() work? e mentre ha fornito alcune buone informazioni, non risponde ancora a quello che sta succedendo qui, che è la mia vera domanda. Sebbene confermi la mia idea che nessun dato è archiviato negli elementi, ma in un oggetto jQuery.

risposta

3

Guardando la fonte di strumenti di Chrome per sviluppatori, ho trovato questo commento intorno alla linea 1564, nella versione 1.9 (GitHub source here, linea 17 all'interno della funzione internalData)

// Only DOM nodes need the global jQuery cache; JS object data is 
// attached directly to the object so GC can occur automatically 

Quindi, che cosa sta accadendo qui, è che quando si passare in nativeObj, memorizzerà i dati in $ .cache, ma altrimenti memorizzerà il valore sull'oggetto jQuery che si passa.

un'occhiata a questo violino: http://jsfiddle.net/tomprogramming/SNqwh/

Ho fatto un paio di modifiche al tuo esempio originale. Il primo è che passo agli oggetti che hai impostato in alto. Il secondo è che si interrogano gli oggetti per un dato di dati chiamato "test", ma che non sarà mai lì - si sta memorizzando un oggetto che ha una proprietà chiamata test in esso - sotto la proprietà di "chiave" .

Alla fine delle istruzioni del registro, ho aggiunto il mio, utilizzando invece la natura orientata agli oggetti di $.data. Ogni volta, ottengo lo stesso risultato. La mia ipotesi è che utilizza il nodo dom sottostante di ogni oggetto jQuery per accedere alla cache globale, che nel tuo caso ha il valore di {test:34}.

Sono d'accordo che questo è un comportamento inaspettato, come sembrerebbe all'utente principiante che si sta selezionando lo stesso elemento, ma credo che questo sia solo un segno di sottolineatura della differenza tra $.data e $(selector).data(). Quest'ultimo usa sempre il nodo dom sottostante (e quindi sempre 'corretto'), mentre il primo usa l'oggetto jQuery che si passa, se disponibile.

MODIFICA: this fiddle sottolinea nuovamente la differenza. Impostare il valore utilizzando $(selector).data() e quindi estrarlo di nuovo con $.data. La 'cache' usata per gli oggetti originali non è cambiata (essendo gli oggetti stessi), ma la cache globale ha, per il nodo DOM sottostante.

Lezione qui: Usa sempre un nodo DOM o $().data. Questo è il "più coerente"

+0

+1 per guardare nei commenti in GitHub. Questo spiega perché posso ottenere risultati diversi con un riferimento jQuery apparentemente simile. Tuttavia, perché 'jWrapped' e' $ ('# tableTab') si comportano in modo diverso? Entrambi gli oggetti jQuery sono corretti? ma non posso ottenere alcun dato se uso il formato '$ .data ($ ('# tableTab'))' che sembra strano per me b/c jQuery di solito accetta i selettori al posto degli elementi. Potrebbe essere b/c 'jWrapped' è un oggetto già inizializzato, mentre' $ ('# tableTab') 'non lo è? Sembra controproducente b/c '$ ('# tableTab) .data()' funziona. Inoltre elaboreresti la tua "lezione qui". – Klik

+0

L'ultimo violino mi ha illuminato per qualcosa. Dove hai scritto 'jSelector.data ('chiave', {test: 57});' e 'jWrapped.data ('chiave', {test: 116});' Sia jSelector che jWrapped sono oggetti jQuery e ognuno avrà il proprio insieme di dati. Questo risolve questo mistero, tranne, perché non funziona $ .data ($ ('# tableTab'))? Inoltre, ho assunto $() restituisce un oggetto jQuery, quindi sarebbe come passare un oggetto jQuery. – Klik

+0

Cercando di seguire il percorso del codice, sembra che i due metodi non seguano nemmeno lo stesso percorso del codice. Uno va direttamente in 'internalData', dove l'altro salta un po 'all'interno di un plugin jQuery. Questo è sicuramente un comportamento strano per jQuery. Per rispondere alla seconda domanda, posso solo rispondere con: non tutti gli oggetti jQuery sono creati uguali: http://jsfiddle.net/tomprogramming/NqR2V/. Mentre il nodo sottostante è lo stesso, gli oggetti stessi sono diversi. –

Problemi correlati