为什么jQuery的.data方法表现得像这样?(可能的错误?)

Kli*_*lik 5 javascript jquery jquery-ui object

这段代码最能说明我的困惑.

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
Run Code Online (Sandbox Code Playgroud)

哇,等等,发生什么事了

1.为什么我得到不同的结果?我只使用了1个选择器并引用了一个元素.

2.为什么对象引用jWrapped和对象不能$( '#tableTab' )产生相同的结果?

3.此外jWrapped,jWrapped[0]正在产生不同的结果?前者是jQuery包装对象,后者是本机DOM对象.基本上他们引用相同的元素与不同的结果!??

//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"}
Run Code Online (Sandbox Code Playgroud)

nativeObj == $( '#tableTab' ) [0] ,这就是我的预期

哇,这很奇怪,为什么不jWrapped == $( nativeObj )呢?

好,jSelector = $( '#tableTab' ) 这也是我的预期

鉴于这些数据,我推断$ .data必须接受本机DOM元素

$( '#tableTab' ).data( 'key' , { test: 78 } );
console.log($( '#tableTab' ).data('key')); // 78
Run Code Online (Sandbox Code Playgroud)

嗯,请原谅我的控制台...不是很酷的男人.

好吧,我庄严困惑和沮丧,我讨厌jQuery和我讨厌JavaScript和我讨厌IE浏览器...好吧,不,我只是讨厌IE浏览器,但这是另一个故事.为什么jQuery表现得那么奇怪?和IE一起玩的太多了我觉得......

我的猜测是它与$ .data在jQuery中的工作方式有关,它实际上并没有将数据附加到元素,而是将数据存储在自己的对象中,并基于解析传递的数据来引用数据它.我找到了一个bug吗?

救命.

我也看了一下jQuery .data()如何工作的?虽然它确实提供了一些很好的信息,但它仍然没有回答这里发生的事情,这是我真正的问题.虽然它确实证实了我的想法,即没有数据存储在元素中,而是存储在jQuery对象中.

Tho*_*nes 3

查看 chrome 开发者工具中的源代码,我在 1.9 版本中的第 1564 行附近发现了此注释(此处为 GitHub 源代码,函数内的第 17 行internalData

// Only DOM nodes need the global jQuery cache; JS object data is
// attached directly to the object so GC can occur automatically
Run Code Online (Sandbox Code Playgroud)

所以,这里发生的事情是,当您传入 时nativeObj,它将把数据存储在 $.cache 中,否则它将把值存储到您传入的 jQuery 对象上。

看看这个小提琴: http://jsfiddle.net/tomprogramming/SNqwh/

我对您原来的示例做了一些更改。第一个是我传入您在顶部设置的对象。第二个是,您在对象中查询一条名为“test”的数据,但该数据永远不会存在 - 您正在存储一个恰好具有名为 test 的属性的对象 - 在“key”属性下。

在日志语句的末尾,我使用面向对象的性质添加了自己的日志语句$.data。每次,我都会得到相同的结果。我的猜测是,它使用每个 jQuery 对象的底层 dom 节点来访问全局缓存,在您的情况下,该缓存的值为{test:34}.

$.data我确实同意这是意外的行为,因为对于新手用户来说,您似乎选择了相同的元素,但我相信这只是和 之间差异的下划线$(selector).data()。后者始终使用底层 dom 节点(因此始终是“正确的”),而前者将使用您传入的 jQuery 对象(如果可用)。

编辑:这个小提琴再次强调了差异。我使用 设置值$(selector).data(),然后使用 再次将其拉出$.data。用于原始对象的“缓存”没有改变(即对象本身),但底层 DOM 节点的全局缓存已经改变。

这里的教训:始终使用 DOM 节点,或者$().data. 这就是“最一致”