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

时间:2013-02-10 06:07:47

标签: 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

哇,等等,发生了什么

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

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

3.此外jWrappedjWrapped[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"}

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

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

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

鉴于这些数据,我推断$ .data必须接受原生DOM元素,但是

$( '#tableTab' ).data( 'key' , { test: 78 } );
console.log($( '#tableTab' ).data('key')); // 78
对不起,请原谅我......不是很酷的人。

好的,我感到非常困惑和沮丧,我讨厌jQuery,我讨厌Javascript,我讨厌IE ... 好吧,我只是讨厌IE,但这是另一个故事。为什么jQuery表现得那么奇怪?和IE一起玩的太多了我想......

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

帮助。

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

1 个答案:

答案 0 :(得分:3)

查看chrome开发人员工具中的来源,我在版本1.9(GitHub source here,第17行,函数internalData)中的第1564行找到了此评论。

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

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

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

我对原始示例进行了一些更改。首先是我传入你在顶部设置的对象。第二个是你在对象中查询一个名为“test”的数据,但是那里不存在 - 你正在存储一个碰巧有一个名为test的属性的对象 - 在“key”的属性下

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

我同意这是出乎意料的行为,因为新手用户认为你选择的是相同的元素,但我相信这只是$.data和{{1}之间差异的下划线。 }。后者总是使用底层的dom节点(因此总是'正确'),而前者将使用你传入的jQuery对象(如果可用)。

编辑:this fiddle再次强调了差异。我使用$(selector).data()设置了值,然后使用$(selector).data()再次将其拉出。用于原始对象的“缓存”没有改变(作为对象本身),但是对于底层DOM节点,全局缓存具有。

此处的课程:始终使用DOM节点或$.data。这是“最一致的”