5

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

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.FurthermorejWrappedjWrapped[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 中的工作方式有关,它实际上并不将数据附加到元素,而是将数据存储在它自己的对象中,并基于解析传递的数据来引用数据它。我发现错误了吗?

帮助。

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

4

1 回答 1

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

所以,这里发生的事情是,当你传入时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. 那是“最一致的”

于 2013-02-10T06:50:20.203 回答